Reputation: 33880
1) What is int
? Is it any different from the struct
System.Int32
? I understand that the former is a C# alias (typedef
or #define
equivalant) for the CLR type System.Int32
. Is this understanding correct?
2) When we say:
IComparable x = 10;
Is that like saying:
IComparable x = new System.Int32();
But we can't new
a struct, right?
or in C like syntax:
struct System.In32 *x;
x=>someThing = 10;
3) What is String
with a capitalized S? I see in Reflector that it is the sealed
String
class, which, of course, is a reference type, unlike the System.Int32
above, which is a value type.
What is string
, with an uncapitalized s, though? Is that also the C# alias for this class?
Why can I not see the alias definitions in Reflector?
4) Try to follow me down this subtle train of thought, if you please. We know that a storage location of a particular type can only access properties and members on its interface. That means:
Person p = new Customer();
p.Name = "Water Cooler v2"; // legal because as Name is defined on Person.
but
// illegal without an explicit cast even though the backing
// store is a Customer, the storage location is of type
// Person, which doesn't support the member/method being
// accessed/called.
p.GetTotalValueOfOrdersMade();
Now, with that inference, consider this scenario:
int i = 10;
// obvious System.object defines no member to
// store an integer value or any other value in.
// So, my question really is, when the integer is
// boxed, what is the *type* it is actually boxed to.
// In other words, what is the type that forms the
// backing store on the heap, for this operation?
object x = i;
Update
Thank you for your answers, Eric Gunnerson and Aaronought. I'm afraid I haven't been able to articulate my questions well enough to attract very satisfying answers. The trouble is, I do know the answers to my questions on the surface, and I am, by no means, a newbie programmer.
But I have to admit, a deeper understanding to the intricacies of how a language and its underlying platform/runtime handle storage of types has eluded me for as long as I've been a programmer, even though I write correct code.
Upvotes: 1
Views: 314
Reputation: 128417
I'll respond to questions 2 and 4 only, because it seems the others have been answered satisfactorily already.
First, let's look at this code from your question:
int i = 10;
object x = i;
Now, it sounds to me like you're overthinking this. Yes, it's true that the System.Object
type includes no member that would represent the int
which has been boxed here. But that doesn't make this case any different from the other code you posted, which you seem to understand perfectly:
Person p = new Customer();
p.Name = "Water Cooler v2";
In this case, the Customer
class derives from the Person
class. There are fields, methods, etc. belonging to Customer
that are not visible from the context of a Person
, but a Customer
is a Person
. In the same way, System.Int32
(which is the same thing as int
, as others have pointed out) derives from System.Object
. It is simply that there are operations you can perform on an int
that are not visible from the context of an object
-- e.g., performing addition, etc. But an int
is an object
.
So the answer to the question "what is actually placed on the heap?" (the heap, by the way, being an implementation detail of the CLR) is actually quite straightforward: an int
is put there.
Now, if I may backtrack a bit, I want to respond to this question:
But we can't
new
a struct, right?
Actually, this is inaccurate. What does the keyword new
do? It sounds like you're thinking in C++ terms, and assuming that if a type is allocated on the stack (again: an implementation detail, mind you), then using the new
keyword makes no sense. But in C#, new
basically just means you're invoking the type's constructor. And value types (structs) have constructors just like reference types (classes); so yes, this line:
IComparable x = 10;
is effectively the same as:
IComparable x = new System.Int32(10); // if System.Int32 had a public
// parameterized constructor
// (which it doesn't, probably
// because that would just
// confuse people)
Now, let me ask you a question: what is the important difference between value types and reference types in .NET? If your answer involves any of the words "stack," "heap," or "allocated," then chances are you're focusing on the wrong thing. What does it matter to us, as developers, where objects are allocated (nitty gritty performance-tweaking-related details aside)? The important difference, as far as I'm concerned, is simply that value types are passed by value (copied) in method calls. Honestly, that's it. That's what matters.
When you view it this way, the big mystery of boxing/unboxing is really not so mysterious. Let's look at this code again:
int i = 10;
object x = i;
We say that in the above code, we are "boxing" the integer i
in the object x
. But what is meant by this term "boxing"? Is it the same as placing values on the heap? How can this be, if heap vs. stack allocation is an unspecified implementation detail?
Remember what I said about value types. The important thing about int
being a value type is that whenever you pass an int
to a method, you're really passing a copy. This is the behavior of all value types, which is the same as saying all types deriving from System.ValueType
. But notice that System.Object
does not derive from System.ValueType
. It's the other way around. object
is a reference type.
So what "boxing" really means is that you're taking an object that, by virtue of its type, is always passed by value, and casting it to a base type (object
) that is passed by reference*.
If I may offer a somewhat silly analogy: Suppose that you go to some bizarre theme park where the following rules apply:
Before you enter the park, you fill in a little form classifying yourself. After turning in this form, you receive a red wristband if you're from New York, or else a blue wristband.
What if you're from New York but you want to ride the Ferris Wheel? Simple: on the form, instead of filling out your classification as "New Yorker," you just write, "Person." Bingo, they give you a blue wristband, and you're in.
The key distinction to be made here is between what objects can do and how they are treated. As I've said multiple times, System.Int32
derives from System.Object
, and so you can cast int
to object
just as easily as you can cast an object of any type to a type from which it derives. All this does is restrict what you are able to do with that object, because only the methods, fields, etc. of the base class are available. Nothing special there. But by casting an int
to object
, you change the way it's treated. Just as by casting yourself in the theme park example to a "Person" -- something less specific than what you really are, a "New Yorker," or in other words a base type -- you changed the way you were treated.
Does that make sense?
*Stating that reference types are "passed by reference" is arguably not a strictly accurate statement and has caused much confusion for many developers (a more accurate statement might be "references to reference types are passed by value"); for a thorough discussion of this subject, you'll need to look elsewhere.
Upvotes: 2
Reputation: 11
1) Yes. "int" is just an alias that C# defines for System.Int32.
2) Your first answer.
3) string is the C# alias for the type System.String. Since nearly everybody has "using System;" in their program, you can either use "string" or "String".
4) You can think of it as an int stored in a reference type box. Even though the type of the box is only visible as "object", the runtime knows that there's an int inside of it.
That's why you can't write:
int i = 10;
object x = i;
short j = (short) x; // this is an error because you can only unbox x as an int.
Much of this is in the C# language reference or in one of the introductory books.
Upvotes: 1
Reputation: 4755
1) int is an alias for the structure System.Int32. You can define any alias you want for a type in C#. For doing that you need to use an using statment similiar to the using statments you normally to import namespaces. For example, if I'd like to create an alias to System.Int64 and call it number, I'd write the following using statment at the beginning of my code file:
using number = System.Int64;
Then, every time I use the alias number on my code the compiler and the intellisense will treat it exactly as System.Int64.
2) Use the default constructor of an System.Int32 is the same as assign 0 to an integer variable.
IComparable x = new System.Int32();
does exaclty the same as the code
IComparable x = 0;
It is possible to use the new operator with structures. The semantics of the new to allocate the memory necessary for an object and invoke constructors. The diference between an object defined as a struct and an object defined as a class is how it is allocated. Struct intances are allocated at the stack, whereas the class instances are allocated at heap.
Some interesting fact is the in C# not everything derivates from object.
3) string is keyword of C# compiler (as the int keyword) that is why you cannot see its definition using Reflector. In fact, the IL code generated by the compiler doesn't even now the existance of those alias, because they are used only by the compiler during the compilation process. After the compilation all string references become a System.String in your compiled code.
4) The answer for this question is too long, so I suggest you to read the following article: Representation and Identity
Upvotes: 0
Reputation: 122674
int
is an alias for System.Int32
. The types are identical.
IComparable x = 10
would be similar to writing var i = 10; IComparable x = i
. The compiler chooses what it thinks is the most likely type for the constant, then does an implicit conversion to IComparable
.
string
is an alias for System.String
, similar to #1. You can't see the alias definitions in Reflector because the alias is part of the C# compiler, not the .NET Framework itself. (It's different in VB.NET, for example.)
A boxed integer or other value type is a reference to the value. You could probably think of it as a pointer with some type information attached. The actual backing type, however, is simply System.Object
.
Upvotes: 5