问题
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 actuallysealed 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