gpt4 book ai didi

c# - 我是否使用嵌套类来防止类实例化或...?

转载 作者:行者123 更新时间:2023-11-30 22:36:14 27 4
gpt4 key购买 nike

我已经阅读了几篇关于何时使用嵌套类的文章,但没有找到解决我的具体问题的文章。

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’。或者,更改其可访问性,使其在外部不可见。”信息:“不要使用公共(public)、 protected 或 protected 内部嵌套类型作为对类型进行分组的方式。为此目的使用命名空间。嵌套类型是最佳设计的场景非常有限。”现在,我相信 Jon Skeet 认为您无法使用 namespace 完成此任务。我只是想确定一下,因为这个错误表明在有限的情况下这是最好的设计,所以如果有更好的设计,我愿意接受想法 :D

此外,它不喜欢从构造函数调用的虚拟调用链。是否有一个原因?有办法解决吗?编辑:具体来说,消息是:“DoNotCallOverridableMethodsInConstructors”。解决方案:“'CompiledLoaderV2.CompiledLoaderV2(String)' 包含一个调用链,该调用链会导致调用类定义的虚拟方法。查看以下调用堆栈以了解意外后果”信息:“不应从构造函数调用在类上定义的虚拟方法。如果派生类重写了该方法,则将调用派生类版本(在调用派生类构造函数之前)”。我觉得如果子类在它们的构造函数中做了一些事情,这可能会成为一个问题,但由于它们没有,我不确定这是一个问题。有没有更好的方法来强制类以某种方式加载,而无需在构造函数中使用抽象方法?

非常感谢您的帮助!

最佳答案

不,你不能用命名空间来做到这一点,尽管你可以用程序集来做到这一点——即防止任何人在程序集之外创建一个实例。

您绝对可以使用嵌套类来做到这一点,但您通常应该将构造函数本身设为私有(private),以防止从该类派生任何其他内容。您也可以将嵌套类本身设为私有(private),除非您需要向外界公开它们。

您可以使用此模式创建一些 Java 枚举,以及有限的工厂。我在 Noda Time 中将它用于受歧视的工会 - 实际细节并不重要,但你可能想看看 the source获取更多灵感。

您不相信从构造函数调用虚拟方法是正确的。它偶尔会有用,但应该非常小心地使用大量文档。

关于c# - 我是否使用嵌套类来防止类实例化或...?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7112666/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com