Reputation: 39
class Program
{
static void Main(string[] args)
{
var p = new Program();
p.Main(args);//instance reference error,use type name instead
var p = new Program();
Program.Main(args);//error disappears
}
}
I think I understand that statics are not associated with object instances, but what I'm having trouble with is aren't classes synonymous with objects? Or aren't classes used in creating objects? So why does the error disappear when I use the class name if classes are essentially objects?
I get that I haven't yet created an instance of Main
and won't be. Is that the only thing that makes the difference? Maybe it's just not being explained properly in this class I'm taking.
Upvotes: 1
Views: 1634
Reputation: 1
Static methods in classes are meant to be connected to the class. Other methods are meant to be connected to objects. This way, you can access static methods without having to create an object. In c++, this the boilerplate code you would use:
className::staticMethod();
Upvotes: -1
Reputation: 659994
Your confusion is a very natural one, and it is exacerbated by the design of C# in this respect. I'll try to explain as we go, and I'll reformulate your questions to be easier to answer:
Is
class
synonymous withobject
?
No. Let's be very, very clear on this point. "Object" has a specific meaning in C#. An object is always an instance of a type. There are two broad kinds of object in C#: reference types which are copied by reference, like string
and value types which are copied by value, like int
.
Later you will learn about boxing, which is the mechanism by which an instance of value type may be used in a context that expects a reference, but don't worry about that for now.
In C# a class defines a reference type. Instances of that class are objects. The class itself is not an object.
The justification for this comes from the real world. The class "all objects which are newspapers" is not itself a newspaper. The class "all people who speak French" is not itself a French speaker. It is a category error to confuse a description of a set of things with a specific example of the thing!
(You may wish to examine closely the design of prototype inheritance languages such as JavaScript. In JS we make a specific object that is the prototypical example of a kind of thing, and we make a constructor object that represents the factory for new examples of that kind of thing; the prototype and the constructor work together to make new instances, and both are genuinely objects. But again, your question is about C#, so let's stick to that for now.)
are classes used in creating objects?
Yes. We instantiate a class with new
; since all classes are reference types, new
produces a reference to a novel object.
So why does the error disappear when i use the class name, if classes are essentially objects?
Classes are not objects, but I understand your confusion. It certainly looks like the class name is being used in a context where you would expect an object. (You might be interested to examine closely the design of languages like Python where classes are objects, but your question is about C# so let's stick to that.)
To resolve this confusion you need to understand that the member access operator, also called the "dot operator", in C# is one of the most flexible and sophisticated operators. This makes it easy to use but hard to understand!
The key thing to understand is that the member access operator always has this form:
thing
to be an object and thing.name
to be an object, it is also possible for either or both to not be an object.When you say p.Main
the compiler says "I know that p
is an instance of Program
, and I know that Main
is a name. Does that make sense?"
The first thing the compiler does is verifies that Program
-- p
's type -- has an accessible member Main
, which it does. At this point overload resolution takes over, and we discover that the only possible meaning of Main
is a static method. This is likely a mistake because p
is an instance, and we're attempting to invoke a static through the instance. C#'s designers could have allowed this -- it is allowed in other languages. But since this is a likely mistake, they disallowed it.
When you type Program.Main
, Program
is not an object. The compiler verifies that Program
refers to a type and types have members. Once again, overload resolution takes over and it determines that the only possible meaning is that Main
is being invoked. Since Main
is static and the receiver -- the thing on the left of the dot -- refers to a type, this is allowed.
Maybe it's just not being explained properly in this class I'm taking.
I edit technical books and other course materials and a great many of them explain these concepts very poorly. Also a great many instructors have vague and confused notions about the relationships between classes, objects, variables, and so on. I encourage you to question your instructor closely on these matters until you are satisfied with their explanations.
That said, once you have a solid grasp on these matters then you can start to take shortcuts. As expert C# programmers we say "p
is an object which..." because we all know that we mean "p
is a variable, the value of which is a reference to an object which..."
I think it is helpful for the beginner to spell it out, but you will very quickly become more relaxed about it.
One other thing that you did not ask but is important:
What about reflection?
.NET has a reflection system which allows you to take things that are not objects, like classes, structs, interfaces, methods, properties, events, and so on, and obtain an object which describes them. (The analogy being that a mirror image is not reality but it sure looks like it enough to understand reality.)
It is important to remember that the reflection object is not the class. It is an object which describes the class. If you use reflection in your program like this:
Type t = typeof(Program);
then the value of t
is a reference to the Type
object that describes the characteristics of class Program
. You could inspect that object and determine that there was a MethodInfo
for method Main
, and so on. But the object is not the class. You cannot say
t.Main();
for example. There are ways to invoke methods via reflection, but it is a mistake to think of the Type
object as being the class. It reflects the class.
Another question you did not ask but is germane to your education:
What you're saying here is that values are instances of objects, but certain programming language constructs such as classes are not objects that can be manipulated like values. Why is it that some programming language constructs in C# are "first class" -- they can be treated as data manipulated by the program -- and some are "second class", and cannot be so manipulated?
That question gets to the crux of language design itself. All language design is a process of examining past languages, observing their strengths and weaknesses, coming up with principles that attempt to build on strengths while mitigating weaknesses, and then resolving the countless contradictions entailed when principles come into conflict with each other.
We all want a camera that is lightweight, inexpensive, and takes great pictures, but as the saying goes, you can only have two. The designers of C# were in a similar position:
And now the big ones:
But like the camera, you can't have all of these at once. C# is a general-purpose programming language designed for programming in the large with a strong static type checker for finding real-world mistakes before they make it into production. It is precisely because we want to find the sort of error you're encountering that we do not allow types to be treated as first-class values. If you treat types as first class then huge amounts of static analysis capability goes out the window!
Other language designers made completely different choices; the consequences of Python saying "classes are a kind of function, and functions are a kind of object" dramatically moves the language towards our desired goal of hierarchical simplicity and first-class treatment of language concepts, and dramatically away from ability to statically determine correctness. That's the right choice for Python, but not for C#.
Upvotes: 10