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

时间:2013-04-26 20:09:59

标签: c# class constructor sealed

我目前正在尝试深入了解.NET框架。当我想知道是否可以创建两个CommandManagers时,我遇到了一个错误:

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

显然这意味着:不要这样做,而且有两个人甚至没有意义。 现在我在收到消息之前遇到了另一个错误:

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

禁止效果相同,但有什么不同。为什么选择一个类没有公共构造函数而不是密封呢?

编辑:

抱歉,我生病了好几天。我进一步混合了两种语言:VB和C#。我打开了两个标签,忽略了一个站在C#上,一个站在VB Code上。一个班级被密封,另一个班级似乎是NonInheritable。我没有意识到这实际上是一样的。现在错误消息变得敏感。

IronPython代码段:

commandManager = CommandManager()

失败
Cannot create instances of CommandManager because it has no public constructors

,而

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

失败了:

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

我误导了这些错误消息,因为我的google和stackoverflow搜索没有回答(当然因为CommandManager总是密封在C#中,而在VB中始终是NonInheritable) 进一步的CommandManager似乎都是密封的,没有公共构造函数。

5 个答案:

答案 0 :(得分:11)

您密封了一个类以防止它被子类化。您删除公共构造函数以防止直接实例化类,通常作为单例模式的一部分。

当然,你可以将两者结合起来。

答案 1 :(得分:2)

Sealed表示您无法继承它。这就是差异。您仍然可以创建实例,但不能继承。

答案 2 :(得分:1)

sealed关键字与该类是否可用作基类有关。你绝对可以实例化一个密封的类。

答案 3 :(得分:0)

密封表示无法从中派生子类的类;您的第二个错误必须是指无法创建特定的子类化尝试,而不是尝试创建密封类本身的实例。

不为类声明任何公共构造函数的主要原因是控制其实例的创建。如上所述,这是在 singleton 模式中完成的。这也可以用于 factory 模式实现。在我的游戏引擎中,我为具有多个版本的定义文件的共享部分的各种解析器执行此操作。有时我会把所有建造者都私有化;有时内部;有时受保护以提供不同的控制机制。在这些情况中,我都没有实际执行单例模式。

以下是此用法的摘录:

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 */
  }
}

此基础结构允许在读取第一行后选择适当的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;
  }
}

答案 4 :(得分:-1)

一些内部数据

  • 关键字static实际上是sealed abstract class [ClassName]

abstract表示必须继承使用它。

sealed从继承中关闭它,因为我们都知道你无法继承static