【发布时间】:2011-10-30 01:43:24
【问题描述】:
我已经阅读了几篇关于何时使用嵌套类的文章,但没有一篇文章能解决我的具体问题。
C# 有一个名为 XmlReader 的类,它只提供一个 Create() 方法。我假设 create 创建了 XmlReader 的子类。如果不是,那么对于这个例子,假设它是。
考虑这种关系:
/// <summary>
/// Class to read information in a file on disk
/// </summary>
interface ILoad
{
/// <summary> Version number of the file </summary>
int Version {get;}
/// <summary> Content of the file </summary>
string Content {get;}
/// <summary> Full path to the file </summary>
string FullPath {get;}
}
/// <summary> Provides base loading functionality </summary>
class LoaderBase : ILoad
{
public int Version {get; protected set;}
public string Content {get; protected set;}
public string FullPath{get; protected set;}
/* Helpers omitted */
protected abstract void Load(string pathToFile);
public static LoaderBase Create(string pathToFile)
{
switch(Path.GetExtension(pathToFile))
{
// Select the correct loader based on the file extension and return
}
return null;//unknown file type
}
}
/// <summary> Base class functionality to load compiled files </summary>
public abstract class CompiledLoaderBase : LoaderBase
{
protected CompiledLoaderBase(string path)
{
Load(path);
}
protected override Load(string path)
{
/* read the file and create an XmlReader from it */
ReadVersionNumber(reader);
ReadContent(reader);
}
protected abstract void ReadVersionNumber(XmlReader reader);
protected abstract void ReadContent(XmlReader reader);
// Wish I could call this Create, but inherited a static Create method already
public static CompiledLoaderBase CreateCompiled(string path)
{
//Figure out which loader to create and return it
// ... Assume we figured out we need V1
return new CompiledLoaderV1(path);
}
// Here's the fun stuff!
protected class CompiledLoaderV1 : CompiledLoaderBase
{
public CompiledLoaderV1(string path)
: base(path)
{}
protected override ReadVersionNumber(XmlReader reader)
{ /* read the version number and store in Version */ }
protected override ReadContent(XmlReader reader)
{ /* read the content and store in Content */ }
}
// ... More classes with their own methods for reading version and content
}
现在,我使用嵌套类来防止用户直接创建特定的加载器;他们必须使用抽象基的 Create* 方法之一。 FxCop 对此大发雷霆,我希望能弄清原因。
它提到不要使用嵌套类,而是使用命名空间。有没有办法通过命名空间来实现这一点?
编辑:具体来说,消息是:“NestedTypesShouldNotBeVisible”。解决方案:“不要嵌套类型 'CompiledLoaderBase+CompiledLoaderV1'。或者,更改其可访问性,使其在外部不可见。”信息:“不要使用公共、受保护或受保护的内部嵌套类型作为对类型进行分组的一种方式。为此目的使用命名空间。嵌套类型是最佳设计的场景非常有限。”现在,我相信 Jon Skeet 发现您无法通过命名空间来实现这一点。我只是想确认一下,因为这个错误表明这是最好的设计在有限的情况下,所以如果有更好的,我愿意接受想法:D
此外,它不喜欢从构造函数调用的虚拟调用链。是否有一个原因?有办法解决吗? 编辑:具体来说,消息是:“DoNotCallOverridableMethodsInConstructors”。解决方案:“'CompiledLoaderV2.CompiledLoaderV2(String)' 包含一个调用链,该调用链会导致调用该类定义的虚拟方法。请查看以下调用堆栈以了解意外后果” 信息:“不应从构造函数调用在类上定义的虚拟方法。如果派生类重写了该方法,则将调用派生类版本(在调用派生类构造函数之前)”。如果子类在它们的构造函数中做了某些事情,我觉得这可能是个问题,但由于它们没有,我不确定这是一个问题。有没有更好的方法来强制类以某种方式加载而不在构造函数中使用抽象方法?
非常感谢您的帮助!
【问题讨论】:
-
FxCop 到底告诉了你什么?提供更多详细信息以及您的问题是什么,否则这将被视为模糊问题并关闭
-
明天我会添加 FxCop 消息。我刚离开办公室