Why are static classes considered “classes” and “r

2019-03-09 09:53发布

问题:

I’ve been pondering about the C# and CIL type system today and I’ve started to wonder why static classes are considered classes. There are many ways in which they are not really classes:

  • A “normal” class can contain non-static members, a static class can’t. In this respect, a class is more similar to a struct than it is to a static class, and yet structs have a separate name.
  • You can have a reference to an instance of a “normal” class, but not a static class (despite it being considered a “reference type”). In this respect, a class is more similar to an interface than it is to a static class, and yet interfaces have a separate name.
  • The name of a static class can never be used in any place where a type name would normally fit: you can’t declare a variable of this type, you can’t use it as a base type, and you can’t use it as a generic type parameter. In this respect, static classes are somewhat more like namespaces.
  • A “normal” class can implement interfaces. Once again, that makes classes more similar to structs than to static classes.
  • A “normal” class can inherit from another class.

It is also bizarre that static classes are considered to derive from System.Object. Although this allows them to “inherit” the static methods Equals and ReferenceEquals, the purpose of that inheritance is questionable as you would call those methods on object anyway. C# even allows you to specify that useless inheritance explicitly on static classes, but not on interfaces or structs, where the implicit derivation from object and System.ValueType, respectively, actually has a purpose.

Regarding the subset-of-features argument: Static classes have a subset of the features of classes, but they also have a subset of the features of structs. All of the things that make a class distinct from the other kinds of type, do not seem to apply to static classes.

Regarding the typeof argument: Making a static class into a new and different kind of type does not preclude it from being used in typeof.

Given the sheer oddity of static classes, and the scarcity of similarities between them and “normal” classes, shouldn’t they have been made into a separate kind of type instead of a special kind of class?

回答1:

Yes, they are very odd. They do have some class-like behavior, like being able to have (static) member variables, and restricting access to members using public/private.

I almost typed "public/protected/private" there, but obviously protected doesn't make sense, because there is no method inheritance of static classes. I think the main reason for this is that because there are no instances, you can't have polymorphism, but that is not really the only reason for inheritance. Polymorphism is great, but sometimes you just want to borrow most of the functionality of the base class and add a few things of your own. Because of this, sometimes you'll see static classes switched to use singleton patterns, just so that it can leverage the some functions from base set of classes. In my opinion this is a hacky attempt to close that gap, and it gets confusing and introduces a lot of unnatural complexity. The other option is aggregation, where the child class methods just pass calls through to the parent class methods, but this is requires a lot of code to stich it all together and isn't really a perfect solution either.

These days, static classes are usually just used as a replacement for global methods, i.e. methods that just provide functionality without being bound to an instance of anything. The OO purists hate any concept of a free/global anything floating around, but you also don't want to have to have an unnecessary instance and object floating around if you just need functionality, so a static "class" provides a middle-ground compromise that both sides can sort of agree with.

So yes, static classes are weird. Ideally, it would be nice if they could be broken into their own concept that provided the flexibility and lightweight ease-of-use that you get from methods that don't need to be bound to an instance (which we have now with static classes), and also group those methods into containers (which we also have now), but also provide the ability to define a base entity from which it will inherit methods (this is the part that is missing now). Also, it would be great it was a seperate concept from classes, for exactly the reasons you raise, it just gets confusing because people naturally expect classes to be instances with properties and methods that can be created and destroyed.



回答2:

It's a class as far as the CLR is concerned. It's just syntactic sugar in the C# compiler, basically.

I don't think there would be any benefit in adding a different name here - they behave mostly like classes which just have static methods and can't be constructed, which is usually the kind of class which became a static class when we moved from C# 1 to C# 2.

Bear in mind that if you want to create a new name for it, that probably means a new keyword too...



回答3:

Your question is "why do I have to type the words static class X rather than foobar X". The answer is, because programmers already associate the word 'class' with 'a bundle of tightly packed encapsulated functionality someone wrote for me'. Which, coincidentally, fits perfectly with the definition of static classes.

They could've used namespaces instead, yes. That's what happens in C++. But the term 'static class' has an advantage here: it implies a smaller and much more tightly coupled group of functionality. For example, you can have a namespace called Qt or boost::asio but a static class called StringUtils or KWindowSystem (to borrow one from KDE).



回答4:

I don't know if this qualifies as an answer, but I would point out that "static classes" are more of a language concept and less of a CLR concept. From the point of view of the CLR, they are just classes, like any other. It's up to the language to enforce all the rules you described.

As such, one advantage of the current implementation is that it does not add further complexity to the CLR, which all CLR-targeting languages would have to understand and model.



回答5:

Sure, they could have been made into a separate kind of thing.

But that would have required additional work in the CLR, the BCL, and across the language teams, and I that would have left other, more important things undone.

From a purely aesthetic point of view, I might agree with you.



回答6:

Good point, it's probably because of historic reasons, i.e. they didn't want to invent something new as static classes already existed.

C++, Pascal (Delphi) and Java all have static classes, and those are what C# is based on.



回答7:

Static classes and "normal" classes (and structs) are containers for executable code (members fields, properties, methods) and they declare a Type. If they had a separate word for this then we would ask the opposite ("if they are so similar, why did you not use the kayword class?"). I'd suggest "CLR via C#", where it's well explained how type resolving, method calling, etc occurs. It works in the same way for "both" classes, just instance members have additional parameter passed in for the instance object.

Classes are not like namespaces because they are only for naming and referencing. They do not affect the functionality of the class.

Classes are also different from interfaces, because interfaces are merely compile-time verification tools and do not have functionality of their own.



回答8:

In my opinion, static classes are considered so because they can embed private fields, public properties and methods, though they are static, and have a fixed address location where each call to the singleton method or property will have its reference.

A structure is more likely a value type as when you write:

var struct1 = new Struct1();
var struct2 = struct1;

each of the properties will have been copied into a new memory location. Furthermore, with a structure, you will be able to change struct2.Property1 value without having it changed within struct1.Property1.

Per opposition, classes are in my understanding reference types, as when you write:

var class1 = new Class1();
var class2 = class1;

Here, the reference is copied. This means that when you change class2.Property1, this same property will also change in class1.Property1. This is because both classes points to the same memory address.

As for static classes, they are considered as reference types as when you change a StaticClass.Property value within a method, this change will get populated everywhere you reference this class. It has only one memory address and can't be copied, so that when another method or property call will occur, this new value will prevail over the old one. Static classes are meant to be shareable accross an entire application, so only one reference for it exists within your application. Therefore making them behave like a class.

A static class, even though singleton pattern is not, I guess, encouraged except for absolute purpose, could represent a real-life object just like a class or an instance of a class. However, since unique-in-the-world-objects seem to be rare enough, we don't really need them to represent a practical object, but merely some logical ones instead, such as tools and so forth, or some other costy-to-instiate objects.

EDIT In fact, a static class is so similar to a class that in Visual Basic, there is no static class, but only a class with static (Shared in Visual Basic) members. The only point to consider is to make this class NotInheritable (sealed in C#). So, C# provides a more implicit functionality by allowing to declare a class static, instead of making it sealed, with an empty default constructor, etc. This is some kind of a shortcut, or syntaxic sugar, like we like to say.

In conclusion, I don't think there would be any benefit or gain having a new keyword for it.



回答9:

Although class types, value types, and interfaces behave in many regards as though they are in three different kinds of things, they are in fact all described using the same kind of Type object; the parentage of a type determines which kind of thing it is. In particular, all types in .NET are class types except for the following:

  • Types other than System.Object which inherit from null; those are interfaces.

  • Types other than System.ValueType or System.Enum which inherit from System.ValueType or System.Enum; those are value types.

  • A few types like pointers and byrefs, which may be identified by Type objects (necessary for things like parameter types) but don't have members the way other types do.

Every type which has members, and whose parentage does not meet either of the above criteria, is considered to be a class. Static classes aren't really classes because of any particular quality they have, but rather because they don't have any quality that would make them be some other named kind of thing, and calling them "static classes" seems easier than inventing some other term to describe them.



回答10:

What about static constructors? I think this is another important aspect to consider in your comparison. Classes and structs support them but interfaces and namespaces do not.

Construction implies instantiation. While the implementation may not actually create an "instance" of a static class, you could view static classes as a singleton instance of a class, to which there can only ever be one reference (the typename itself). If you could inherit static classes, you would break the singleton notion. If you could declare variables of the type, you might expect them to be cleaned up by the garbage collector when they are no longer referenced.

Why are they classes instead of structs? When I think of structs (value types), I think about values on the stack. Their existence is (typically) very short and they are copied frequently. This again breaks the single reference singleton notion above.