简体   繁体   English

C#密封类与无公共构造函数

[英]C# sealed class vs. no public constructor

I am currently trying to get deeper into the .NET framework. 我目前正在尝试更深入地了解.NET框架。 I ran across an error while I was wondering if I could create two CommandManagers: 我想知道是否可以创建两个CommandManager时遇到错误:

Cannot create an instance of CommandManager because it has no public constructors.

Obviously it means: don't do it, and it might not even make sense to have two of them. 显然,这意味着:不要这样做,并且拥有两个可能甚至没有意义。 Now I came across an other error before with the message: 现在我在遇到此消息之前遇到了另一个错误:

Cannot create an instance of ... because it is sealed

The effect is the same in prohibiting but what is the difference. 禁止的效果相同,但有什么区别。 Why does one choose a class to have no public constructors vs making it sealed? 为什么选择一个没有公共构造函数的类而不是密封它?

EDIT: 编辑:

Sorry I was ill for a couple of days. 对不起,我病了几天。 Further I mixed two languages: VB and C#. 此外,我混合了两种语言:VB和C#。 I had two tabs open and overlooked that one was standing on C# and one on VB Code. 我打开了两个选项卡,却忽略了一个站在C#上,一个站在VB代码上。 One class was sealed the other seemed to be NonInheritable. 一类是密封的,另一类似乎是不可继承的。 I didn't realize that this is actually the same. 我没有意识到这实际上是相同的。 Now the error messages make sens. 现在,错误消息变得有意义。

IronPython Code snippet: IronPython代码段:

commandManager = CommandManager()

fails with 失败于

Cannot create instances of CommandManager because it has no public constructors

while

class MyCommandManager(CommandManager):
    return super(MyCommandManager, self).__init__(*args, **kwargs)()

fails with: 失败与:

cannot derive from System.Windows.Input.CommandManager because it is sealed

I was mislead by these errormessages and since my google and stackoverflow search returned no answer (naturally because CommandManager is always sealed in C# while always NonInheritable in VB) Further CommandManager seems to be both sealed and having no public constructor. 我被这些错误消息误导了,因为我的Google和stackoverflow搜索未返回任何答案(自然是因为CommandManager始终在C#中密封,而在VB中始终是NonInheritable),进一步的CommandManager似乎都是密封的并且没有公共构造函数。

You seal a class to prevent it from being subclassed. 您密封一个类以防止其被子类化。 You remove public constructors to prevent a class from being directly instantiated, usually as part of a singleton pattern. 您删除公共构造函数以防止直接实例化类,通常将其作为单例模式的一部分。

You can, of course, combine both. 您当然可以将两者结合起来。

Sealed means you cannot inherit from it. Sealed意味着您不能从中继承。 That's the difference here. 这就是这里的区别。 You can still create an instance, but cannot inherit. 您仍然可以创建实例,但是不能继承。

The sealed keyword has to do with whether the class can be used as a base class. sealed关键字与该类是否可以用作基类有关。 You can absolutely instantiate a sealed class. 您可以绝对实例化一个密封的类。

Sealed denotes a class from which subclasses cannot be derived; 密封表示无法从其派生子类的类; your second error would have to refer to the inability to create a specific subclassing attempt, not an attempt to create an instance of the sealed class itself. 您的第二个错误将涉及无法创建特定的子类尝试,而不是尝试创建密封类本身的实例。

The main reason for not declaring any public constructors for a class are to control the creation of its instances. 不声明类的任何公共构造函数的主要原因是要控制其实例的创建。 This is done in the singleton pattern as noted. 如上所述,这是按照单例模式完成的。 This might also be done for a factory pattern implementation. 对于工厂模式实现也可以这样做。 In my game engine I do it for various parsers of shared portions of definition files with multiple versions. 在我的游戏引擎中,我对具有多个版本的定义文件共享部分的各种解析器执行此操作。 Sometimes I make all constructors private; 有时,我将所有构造函数设为私有。 sometimes internal; 有时是内部的; and sometimes protected to provide different control mechanisms. 有时受到保护以提供不同的控制机制。 In none of these cases am I actually enforcing a singleton pattern. 在所有这些情况下,我实际上都没有执行单例模式。

Here is an extract of this usage: 这是此用法的摘录:

internal abstract class AbstractParser {
  protected TextReader              Reader    { get; set; }
  // etc.
}

internal abstract class MapParser : AbstractParser, IParser<IMapDefinition> {
  public abstract IMapDefinition Parse();
  protected internal MapParser(TextReader reader) : this() { 
    Reader = reader;
  }
  public IMapDefinition Parse(Func<MapHeader, string[], int[][],
    HexsideData[,], List<IHpsPlaceName>, int, IMapDefinition> factory
  ) {
    var header     = ParseMapHeader(1);
    var terrain    = ParseTerrain(header.Size);
    var elevations = ParseElevation(header.Size);
    var feature    = ParseFeatures( header.Size);
    var placeNames = ParsePlaceNames();

    return factory(header, terrain, elevations, feature, placeNames, MaxElevationLevel);
  }
  // etc.
}

internal class MapV1Parser : MapParser {
  internal MapV1Parser(TextReader reader) : base(reader) {}

  public override IMapDefinition Parse() {
    return base.Parse((h,t,e,f,p,xe) => (new MapDefinitionV1(h,t,e,f,p,xe)));
  }
}

internal class MapV2Parser : MapParser {
  private readonly Regex regexHeaderLine3;
  internal MapV2Parser(TextReader reader) : base(reader) {
    regexHeaderLine3  = new Regex(@"^([-]?[0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-1])$",
                                  RegexOptions.None);
  }
  public override IMapDefinition Parse() {
    return base.Parse((h,t,e,f,p,xe) => (new MapDefinitionV2(h,t,e,f,p,xe)));
  }
  protected override Line3 ParseHeaderLine3() {  
    /* Definition override for V3 */
  }
}

This infrastructure allows the selection of the appropriate MapParser after reading the first line as follows: 在读取第一行之后,此基础结构允许选择适当的MapParser,如下所示:

internal static IParser<IMapDefinition> GetMapParser(TextReader reader) {
  string line = reader.ReadLine();
  short version;
  if (!short.TryParse(line, out version))
    Utils.ThrowInvalidDataException("MapParser",1,"Header","Non-integer version number",null,line);

  switch(version) {
    case 1:   return new MapV1Parser(reader);
    case 2:   return new MapV2Parser(reader);
    default:  Utils.ThrowInvalidDataException("MapParser",1,"Header","Unknown version number",
                null,version);
              return null;
  }
}

Some inside data 一些内部数据

  • the keyword static is actually sealed abstract class [ClassName] 关键字static实际上是sealed abstract class [ClassName]

Where abstract says it must be inherited to use. abstract表示必须继承才能使用。

Where sealed closes it from inherit, because we all know you cant inherit static sealed关闭了继承的位置,因为我们都知道您不能继承static

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM