C# sealed class vs. no public constructor

三世轮回 提交于 2019-12-13 08:26:32

问题


I am currently trying to get deeper into the .NET framework. I ran across an error while I was wondering if I could create two CommandManagers:

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#. I had two tabs open and overlooked that one was standing on C# and one on VB Code. 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:

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.


回答1:


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.




回答2:


Sealed means you cannot inherit from it. That's the difference here. You can still create an instance, but cannot inherit.




回答3:


The sealed keyword has to do with whether the class can be used as a base class. You can absolutely instantiate a sealed class.




回答4:


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:

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;
  }
}



回答5:


Some inside data

  • the keyword static is actually sealed abstract class [ClassName]

Where abstract says it must be inherited to use.

Where sealed closes it from inherit, because we all know you cant inherit static



来源:https://stackoverflow.com/questions/16244430/c-sharp-sealed-class-vs-no-public-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!