Can C# structs coming from the unmanaged world be "live"-updating? - c#

Suppose I get an IntPtr pointer to a struct from an unmanaged library. Is there any way, in C#, to obtain a "live" struct from this pointer, so that if I make a call that modifies the unmanaged struct, my "live" struct reflects this immediately?
I believe the standard approach is to construct a copy of the data using marshalling, which can't be "live" like this for various reasons (struct layout, data type compatibility, not residing in the .NET managed memory). But I couldn't find any explicit confirmation that "live" structs are impossible in C# though. Are they?
What's the closest I can get to such "live" structs without going to C++/CLI?

Try using the UnmanagedMemoryStream:
This class supports access to unmanaged memory using the existing stream-based model and does not require that the contents in the unmanaged memory be copied to the heap.
This means you will be seeking/reading/resetting the stream, but this avoids the marshalling. It's still not live in the sense you'd want to probably want to wrap these accesses in .NET properties.
Another alternative: maybe you could use System.Buffer, after getting the unmanaged pointer. You may need to do some clever casting.

Technically, you CAN set up a structure whose data is "live" to changes made elsewhere. However, you want to think VERY carefully about whether you SHOULD.
By its very definition in C#, a struct is a "value type". That means that one instance is one value, like "5", and any change to that value conceptually results in a new value. 5+1==6; that doesn't mean that 5 "becomes" 6 when you add 1, it means that two values 5 and 1, when added, equal 6.
Value types in programming also have another idiosyncrasy with reference types; they are passed "by value", meaning that they are considered cheap enough to "clone" when a value is passed as a parameter. Any change that could be made to the variable's value (or child properties) while in the method is discarded when the call is complete, becauwse all of the changes were made to a new copy of the struct on the top level of the stack, instead of a reference to the original object residing lower in the stack. You must explicitly override this behavior by using the ref or out keywords, in effect specifically stating that the original value SHOULD change based on what happens in the method.
Most objects implemented as structs force you to deal with them according to these rules by being immutable; once you've created one, you cannot set its fields/properties directly. You must instead call various methods on that struct which will result in the creation of a new struct.
If you wanted to create a class that would reflect the most current data coming from unmanaged land, first off I would make it a "class", so that there is no confusion about the behavior of the object when you pass it or attempt to change its members. Then, you would basically create a "wrapper" that used Kit's aforementioned UnmanagedMemoryStream to get/set values that you exposed as properties. That would give you a "reactive" object that could be polled to get whatever the unmanaged code had most recently set, and also to write out new values to the correct places in memory. Be VERY careful; this code will not be "safe" (especially if you write back out to it), and hooks into unmanaged code via pointers is one of the few places in .NET where you can intentionally crash not just your program and the unmanaged C++ program, but the entire machine.

Related

What is the hidden value of the pointer/reference assigned to reference type variables?

int number = 1
The value of number is 1 because it is a value type
What is the actual value of the pointer that is assigned to reference type variables?
Is it an int or string? Or is it some bits? What would it look like if you write it out? Is it possible to assign a reference to a variable using that value?
Question harrysQuestion = new Question();
harrysQuestion is just a pointer or reference to the new Question. So what is the value of that pointer? The same value that is assigned to another Question variable if I do this:
Question harrysQuestionAgain = harrysQuestion;
Is it a number that points to some position in my computers memory? Is it an actual C# value variable behind the scenes?
Is it a number that points to some position in my computers memory?
Conceptually, references and pointers are separate but related. In reality they are virtually interchangeable, with the distinction that the GC knows how to walk and fixup references (garbage collection etc), but not pointers (and there are other things about how fixed works in terms of a hack in the value, allowing a reference value found on the stack to be interpreted as "pinned" cheaply). In reality, they are so close to each-other in all implementations (for performance reasons) that you can think of them as kinda the same.
It is very rare that you'd actually want to get the "value" of a reference (rather than dereferencing it), and unless you pin the object first you need to be very careful about doing so as the address can change (and the pointer version will not be corrected). The need for this use-case actually increases slightly with the upcoming "pipelines" work, so the corefxlab / myget version of the Unsafe utility type actually provides some methods to facilitate the exchange of references / pointers (including interior pointers/references into objects), but: unless you're doing something low level you'll probably never need that.
Per request (comments): I mentioned "pinning" and "fixed" - the problem here is that .NET has a "compacting" garbage collector, which is allowed to move objects around at runtime, as long as it promises to fix all the references and make sure that you never notice this from managed code. What it doesn't promise is to fix pointers. So: if you're going to be looking at any object as a pointer, you need to tell the runtime (and in particular: the garbage collector) to not move that object at all, or at least until you tell it that you're done. This is what "pinning" is. There are two ways to "pin":
for long-term pins (typically of things like byte[] buffers that you're going to store as a field in an object and pass to unmanaged code as a pointer), you can take a GCHandle against an object, which gets logged in a global structure that the GC knows to look at
for short-term pins of references that are on a stack, the fixed keyword does some voodoo that lets the GC (which always looks at every stack) know that a reference - and thus the object referred to (the object at that address) - should be considered pinned, without needing to constantly add/remove to a global structure
As a perhaps interesting side note: "interior references" and references to value types are a concept that only exists on the stack - not as fields on a type that could end up on the heap (which means any class or struct except for the new ref struct concept). They work the same as regular references, but the target of those references are the contents themselves, not the start of the object header. That means that
var fieldReference = ref this._someField;
or
SomeOtherMethod(ref this._someField);
or
SomeOtherMethod(ref someArray[index]);
work inside a method as long as that interior reference is only on the stack (i.e. no async / yield / captured-variables / etc); the GC is happy to do the overhead of resolving interior pointers to objects but only for the stacks - to reduce the overall scale of the work involved.

Alias for long lookups

I am working on a project that has nested Lists of classes. hence my code look like this when I want to get a variable.
MainClass.subclass1[element1].subClass2[element2].subClass3[element3].value;
I was wondering how I could get an alias for subClass3 so I can get all the variables in it without having to look in all the subclasses, like this.
subClass3Alias.value
in c++ this would be easy simply have a pointer pointing to it, but C# does not really have pointers.
No need for pointers – types in C# are usually reference types anyway, meaning that you can just copy them and they will refer to the original object (like pointers in C++):
var subclassAlias = MainClass.subclass1[element1].subClass2[element2].subClass3[element3];
Now you can use subclassAlias.value.
A slightly different thing occurs if your type happens to be a value type: in that case, the above will still work – but subclassAlias will be a value copy of the original value, meaning that changes to subclassAlias will not be reflected in the original object.
That said, this looks like suspicious code anyway – normally such deep levels of nesting are a sign of bad design and violate the Law of Demeter.
(Incidentally, in C++ you wouldn’t use pointers either.)

Why does a field in a struct lose its value when a field in an identical class does not?

I have a Struct with a field in it that loses its value. I can declare the field static and that solves the problem. I can also just change struct to class (changing nothing else) and that also solves the problem. I was just wondering why this is?
Structs are passed by value. In other words, when you pass a struct, you're passing a copy of its value. So if you take a copy of the value and change it, then the original will appear unchanged. You changed the copy, not the original.
Without seeing your code I cannot be sure, but I figure this is what's happening.
This doesn't happen for classes as they're passed by reference.
It's worth mentioning that this is why structs should be immutable -- that is, that once they're created, they do not change their value. Operations that provide modified versions return new structs.
EDIT: In the comments below, #supercat suggests that mutable properties can be more convenient. However property setters on structs can cause weird failures too. Here's an example that can catch you by surprise unless you deeply understand how structs work. For me, it's reason enough to avoid mutable structs altogether.
Consider the following types:
struct Rectangle {
public double Left { get; set; }
}
class Shape {
public Rectangle Bounds { get; private set; }
}
Ok, now imagine this code:
myShape.Bounds.Left = 100;
Perhaps surprisingly, This has no effect at all! Why? Let's re-write the code in longer yet equivalent form:
var bounds = myShape.Bounds;
bounds.Left = 100;
It's easier to see here how the value of Bounds is copied to a local variable, and then its value is changed. However at no point is the original value in Shape updated.
This is pretty compelling evidence to make all public structs immutable. If you know what you're doing, mutable structs can be handy, but personally I only really use them in that form as private nested classes.
As #supercat points out, the alternative is a little unsightly:
myShape.Bounds = new Rectangle(100, myShape.Bounds.Top,
myShape.Bounds.Width, myShape.Bounds.Height);
Sometimes it's more convenient to add helper methods:
myShape.Bounds = myShape.Bounds.WithLeft(100);
When a struct is passed by value, the system will make a copy of the struct for the callee, so it can see its contents, and perhaps modify its own copy, but but cannot affect the fields in the caller's copy. It's also possible to pass structs by ref, in which case the callee will be able to work with the caller's copy of the struct, modifying it if desired, and even pass it by ref to other functions which could do likewise. Note that the only way the called function can make the caller's copy of the struct available to other functions, though, is to pass it by ref, and the called function can't return until all functions to which it has passed the struct by ref have also returned. Thus, the caller can be assured that any changes which might occur to the structure as a consequence of the function call will have occurred by the time it returns.
This behavior is different from class objects; if a function passes a mutable class object to another function, it has no way of knowing if or when that other function will cause that object to be mutated immediately or at any future time, even after the function has finished running. The only way one can ever be sure that any mutable object won't be mutated by outside code is to be the sole holder of that object from the moment of its creation until its abandonment.
While one who is not used to value semantics may initially be "surprised" at the fact passing a struct by value simply gives the called function a copy of it, and assigning one struct storage location to another simply copies the contents of the struct, the guarantees that value types offer can be very useful. Since Point is a structure, one can know that a statement like MyPoints[5].X += 1; (assuming MyPoints is an array) will affect MyPoints[5].X but will not affect any other Point. One can further be assured that the only way MyPoints[5].X will change is if either MyPoints gets replaced with another array, or something writes to MyPoints[5]. By contrast, Point were a class and MyPoint[5] had ever been exposed to the outside world, the only way of knowing whether the aforementioned statement would affect field/property X of any other storage locations of type Point would be to examine every single storage location of type Point or Object that existed anywhere within the code to see if it pointed to the same instance as MyPoints[5]. Since there's no way for code to examine all of the storage locations of a particular type, such assurance would be impossible if Point[5] had ever been exposed to the outside world.
There is one annoying wrinkle with structs, though: generally, the system will only allow structures to be passed by ref if the called code is allowed to write to the structure in question. Struct method calls and property getters, however, receive this as a ref parameter but do not have the above restriction. Instead, when invoking a struct method or property getter on a read-only structure, the system will make a copy of the structure, pass that copy by ref to the method or property getter, and then discard it. Since the system has no way of knowing whether a method or property getter will try to mutate this, it won't complain in such cases--it will just generate silly code. If one avoids mutating this in anything other than property setters (the system won't allow the use of property setters on read-only structures), however, one can avoid problems.

C# to C++ 'Gotchas'

I have been developing a project that I absolutely must develop part-way in C++. I need develop a wrapper and expose some C++ functionality into my C# app. I have been a C# engineer since the near-beginning of .NET, and have had very little experience in C++. It still looks very foreign to me when attempting to understand the syntax.
Is there anything that is going to knock me off my feet that would prevent me from just picking up C++ and going for it?
C++ has so many gotchas that I can't enumerate them all. Do a search for "C# vs C++". A few basic things to know:
In C++:
struct and a class are basically the same thing (Default visibility for a struct is public, it's private for a class).
Both struct and class can be created either on the heap or the stack.
You have to manage the heap yourself. If you create something with "new", you have to delete it manually at some point.
If performance isn't an issue and you have very little data to move around, you can avoid the memory management issue by having everything on the stack and using references (& operator).
Learn to deal with .h and .cpp. Unresolved external can be you worse nightmare.
You shouldn't call a virtual method from a constructor. The compiler will never tell you so I do.
Switch case doesn't enforce "break" and go thru by default.
There is not such a thing as an interface. Instead, you have class with pure virtual methods.
C++ aficionados are dangerous people living in cave and surviving on the fresh blood of C#/java programmers. Talk with them about their favorite language carefully.
Garbage collection!
Remember that everytime you new an object, you must be responsible for calling delete.
There are a lot of differences, but the biggest one I can think of that programmers coming from Java/C# always get wrong, and which they never realize they've got wrong, is C++'s value semantics.
In C#, you're used to using new any time you wish to create an object. And whenever we talk about a class instance, we really mean "a reference to the class instance". Foo x = y doesn't copy the object y, it simply creates another reference to whatever object y references.
In C++, there's a clear distinction between local objects, allocated without new (Foo f or Foo f(x, y), and dynamically allocated ones (Foo* f = new Foo() or Foo* f = new Foo(x, y)). And in C# terms, everything is a value type. Foo x = y actually creates a copy of the Foo object itself.
If you want reference semantics, you can use pointers or references: Foo& x = y creates a reference to the object y. Foo* x = &y creates a pointer to the address at which y is located. And copying a pointer does just that: it creates another pointer, which points to whatever the original pointer pointed to. So this is similar to C#'s reference semantics.
Local objects have automatic storage duration -- that is, a local object is automatically destroyed when it goes out of scope. If it is a class member, then it is destroyed when the owning object is destroyed. If it is a local variable inside a function, it is destroyed when execution leaves the scope in which it was declared.
Dynamically allocated objects are not destroyed until you call delete.
So far, you're probably with me. Newcomers to C++ are taught this pretty soon.
The tricky part is in what this means, how it affects your programming style:
In C++, the default should be to create local objects. Don't allocate with new unless you absolutely have to.
If you do need dynamically allocated data, make it the responsibility of a class. A (very) simplified example:
class IntArrayWrapper {
explicit IntArrayWrapper(int size) : arr(new int[size]) {} // allocate memory in the constructor, and set arr to point to it
~IntArrayWrapper() {delete[] arr; } // deallocate memory in the destructor
int* arr; // hold the pointer to the dynamically allocated array
};
this class can now be created as a local variable, and it will internally do the necessary dynamic allocations. And when it goes out of scope, it'll automatically delete the allocated array again.
So say we needed an array of x integers, instead of doing this:
void foo(int x){
int* arr = new int[x];
... use the array ...
delete[] arr; // if the middle of the function throws an exception, delete will never be called, so technically, we should add a try/catch as well, and also call delete there. Messy and error-prone.
}
you can do this:
void foo(int x){
IntArrayWrapper arr(x);
... use the array ...
// no delete necessary
}
Of course, this use of local variables instead of pointers or references means that objects are copied around quite a bit:
Bar Foo(){
Bar bar;
... do something with bar ...
return bar;
}
in the above, what we return is a copy of the bar object. We could return a pointer or a reference, but as the instance created inside the function goes out of scope and is destroyed the moment the function returns, we couldn't point to that. We could use new to allocate an instance that outlives the function, and return a function to that -- and then we get all the memory management headaches of figuring out whose responsibility it is to delete the object, and when that should happen. That's not a good idea.
Instead, the Bar class should simply be designed so that copying it does what we need. Perhaps it should internally call new to allocate an object that can live as long as we need it to. We could then make copying or assignment "steal" that pointer. Or we could implement some kind of reference-counting scheme where copying the object simply increments a reference counter and copies the pointer -- which should then be deleted not when the individual object is destroyed, but when the last object is destroyed and the reference counter reaches 0.
But often, we can just perform a deep copy, and clone the object in its entirety. If the object includes dynamically allocated memory, we allocate more memory for the copy.
It may sound expensive, but the C++ compiler is good at eliminating unnecessary copies (and is in fact in most cases allowed to eliminate copy operations even if they have side effects).
If you want to avoid copying even more, and you're prepared to put up with a little more clunky usage, you can enable "move semantics" in your classes as well as (or instead of) "copy semantics". It's worth getting into this habit because (a) some objects can't easily be copied, but they can be moved (e.g. a Socket class), (b) it's a pattern established in the standard library and (c) it's getting language support in the next version.
With move semantics, you can use objects as a kind of "transferable" container. It's the contents that move. In the current approach, it's done by calling swap, which swaps the contents of two objects of the same type. When an object goes out of scope, it is destructed, but if you swap its contents into a reference parameter first, the contents escape being destroyed when the scope ends. Therefore, you don't necessarily need to go all the way and use reference counted smart pointers just to allow complex objects to be returned from functions. The clunkiness comes from the fact that you can't really return them - you have to swap them into a reference parameter (somewhat similar to a ref parameter in C#). But the language support in the next version of C++ will address that.
So the biggest C# to C++ gotcha I can think of: don't make pointers the default. Use value semantics, and instead tailor your classes to behave the way you want when they're copied, created and destroyed.
A few months ago, I attempted to write a series of blog posts for people in your situation:
Part 1
Part 2
Part 3
I'm not 100% happy with how they turned out, but you may still find them useful.
And when you feel that you're never going to get a grip on pointers, this post may help.
No run-time checks
One C++ pitfall is the behaviour when you try to do something that might be invalid, but which can only be checked at runtime - for example, dereferencing a pointer that could be null, or accessing an array with an index that might be out of range.
The C# philosophy emphasises correctness; all behaviour should be well-defined and, in cases like this, it performs a run-time check of the preconditions and throws well-defined exceptions if they fail.
The C++ philosophy emphasises efficiency, and the idea that you shouldn't pay for anything you might not need. In cases like this, nothing will be checked for you, so you must either check the preconditions yourself or design your logic so that they must be true. Otherwise, the code will have undefined behaviour, which means it might (more or less) do what you want, it might crash, or it might corrupt completely unrelated data and cause errors that are horrendously difficult to track down.
Just to throw in some others that haven't been mentioned yet by other answers:
const: C# has a limited idea of const. In C++ 'const-correctness' is important. Methods that don't modify their reference parameters should take const-references, eg.
void func(const MyClass& x)
{
// x cannot be modified, and you can't call non-const methods on x
}
Member functions that don't modify the object should be marked const, ie.
int MyClass::GetSomething() const // <-- here
{
// Doesn't modify the instance of the class
return some_member;
}
This might seem unnecessary, but is actually very useful (see the next point on temporaries), and sometimes required, since libraries like the STL are fully const-correct, and you can't cast const things to non-const things (don't use const_cast! Ever!). It's also useful for callers to know something won't be changed. It is best to think about it in this way: if you omit const, you are saying the object will be modified.
Temporary objects: As another answer mentioned, C++ is much more about value-semantics. Temporary objects can be created and destroyed in expressions, for example:
std::string str = std::string("hello") + " world" + "!";
Here, the first + creates a temporary string with "hello world". The second + combines the temporary with "!", giving a temporary containing "hello world!", which is then copied to str. After the statement is complete, the temporaries are immediately destroyed. To further complicate things, C++0x adds rvalue references to solve this, but that's way out of the scope of this answer!
You can also bind temporary objects to const references (another useful part of const). Consider the previous function again:
void func(const MyClass& x)
This can be called explicitly with a temporary MyClass:
func(MyClass()); // create temporary MyClass - NOT the same as 'new MyClass()'!
A MyClass instance is created, on the stack, func2 accesses it, and then the temporary MyClass is destroyed automatically after func returns. This is convenient and also usually very fast, since the heap is not involved. Note 'new' returns a pointer - not a reference - and requires a corresponding 'delete'. You can also directly assign temporaries to const references:
const int& blah = 5; // 5 is a temporary
const MyClass& myClass = MyClass(); // creating temporary MyClass instance
// The temporary MyClass is destroyed when the const reference goes out of scope
Const references and temporaries are frequent in good C++ style, and the way these work is very different to C#.
RAII, exception safety, and deterministic destructors. This is actually a useful feature of C++, possibly even an advantage over C#, and it's worth reading up on since it's also good C++ style. I won't cover it here.
Finally, I'll just throw in this is a pointer, not a reference :)
The traditional stumbling blocks for people coming to C++ from C# or Java are memory management and polymorphic behavior:
While objects always live on the heap and are garbage collected in C#/Java, you can have objects in static storage, stack or the heap ('free store' in standard speak) in C++. You have to cleanup the stuff you allocate from the heap (new/delete). An invaluable technique for dealing with that is RAII.
Inheritance/polymorphism work only through pointer or reference in C++.
There are many others, but these will probably get you first.
Virtual destructors.
Header files! You'll find yourself asking, "so why do I need to write method declarations twice every time?"
Pointers and Memory Allocation
...I'm a C# guy too and I'm still trying to wrap my head around proper memory practices in C/C++.
Here is a brief overview of Managed C++ here. An article about writing an Unmanaged wrapper using the Managed C++ here. There is another article here about mixing Unmanaged with Managed C++ code here.
Using Managed C++ would IMHO make it easier to use as a bridge to the C# world and vice versa.
Hope this helps,
Best regards,
Tom.
The biggest difference is C#'s reference semantics (for most types) vs. C++'s value semantics. This means that objects are copied far more often than they are in C#, so it's important to ensure that objects are copied correctly. This means implementing a copy constructor and operator= for any class that has a destructor.
Raw memory twiddling. Unions, memsets, and other direct memory writes. Anytime someone writes to memory as a sequence of bytes (as opposed to as objects), you lose much of the ability to reason about the code.
Linking
Linking with external libraries is not as forgiving as it is in .Net, $DEITY help you if you mix something compiled with different flavors of the same msvcrt (debug, multithread, unicode...)
Strings
And you'll have to deal with Unicode vs Ansi strings, these are not exactly the same.
Have fun :)
The following isn't meant to dissuade in any way :D
C++ is a minefield of Gotcha's, it's relatively tame if you don't use templates and the STL -- and just use object orientation, but even then is a monster. In that case object based programming (rather than object-oriented programming) makes it even tamer -- often this form of C++ is enforced in certain projects (i.e., don't use any features that have even a chance of being naively used).
However you should learn all those things, as its a very powerful language if you do manage to traverse the minefield.If you want to learn about gotcha's you better get the books from Herb Sutter, Scott Myers, and Bjarne Stroustrup. Also Systematically going over the C++ FAQ Lite will help you to realize that it indeed does require 10 or so books to turn into a good C++ programmer.

Questions about Structs

MSDN says that a class that would be 16 bytes or less would be better handled as a struct [citation].
Why is that?
Does that mean that if a struct is over 16 bytes it's less efficient than a class or is it the same?
How do you determine if your class is under 16 bytes?
What restricts a struct from acting like a class? (besides disallowing parameterless constructors)
There are a couple different answers to this question, and it is a bit subjective, but some reasons I can think of are:
structs are value-type, classes are reference type. If you're using 16 bytes for total storage, it's probably not worth it to create memory references (4 to 8 bytes) for each one.
When you have really small objects, they can often be pushed onto the IL stack, instead of references to the objects. This can really speed up some code, as you're eliminating a memory dereference on the callee side.
There is a bit of extra "fluff" associated with classes in IL, and if your data structure is very small, none of this fluff would be used anyway, so it's just extra junk you don't need.
The most important difference between a struct and a class, though, is that structs are value type and classes are reference type.
By "efficient", they're probably talking about the amount of memory it takes to represent the class or struct.
On the 32-bit platform, allocating an object requires a minimum of 16 bytes. On a 64-bit platform, the minimum object size is 24 bytes. So, if you're looking at it purely from the amount of memory used, a struct that contains less than 16 bytes of data will be "better" than the corresponding class.
But the amount of memory used is not the whole story. Value types (structs) are fundamentally different than reference types (classes). Structs can be inconvenient to work with, and can actually cause performance problems if you're not careful.
The real answer, of course, is to use whichever works best in your situation. In most cases, you'll be much better off using classes.
Check this link, I found it on one of the answers in SO today: .NET Type Internals. You can also try searching SO and Googling for "reference types vs value types" for differences between structs and classes.
What restricts a struct from acting like a class?
There are many differences. You cannot inherit from a struct, for example.
You can't have virtual methods, so you cannot use a struct to implement an interface. Instance methods in structs can access struct's private fields, but apart from that they behave a lot like auxilirary "helper" functions (for immutable structs, they sometimes don't even need to access private data). So I find them to be not as near as "valuable" as class methods.
structs are different from classes because they are stored on the stack, and not on the heap. That means that every time you call a method with the struct as parameter, a copy is created and passed to the method. That is why large structs are extremely inefficient.
I would actively discourage to use structs nevertheless, because it could cause some subtle bugs: e.g. when you change a field of a struct, its not going to be reflected for the caller (because you only changed the copy) - which is completely different behavior to classes.
So the 16 bytes I think is a reasonable maximum size of a struct, but still in most cases it is better to have a class. If you still want to create a struct, try to make it immutable at least.
This is due to the different way that the CLR handles structs and classes. Structs are value types which means they live on the stack rather than in the managed heap. It is a good rule of thumb to keep structs small because once you start passing them as method arguments you will incur overhead as structs are copied in their entirety when passed to a method.
Since classes pass a copy of their reference to methods they incur much less overhead when used as method arguments.
The best way to determine the size of your class is to total the number of bytes required by all the members of your class plus an extra 8 bytes for CLR overhead stuff (the sync block index and the reference to the type of the object).
In memory, the struct will hold the data directly, while a class will behave more like a pointer. That alone makes an important difference, since passing the struct as a parameter to a method will pass its values (copy them on the stack), while the class will pass the reference to the values. If the struct is big, you will be copying a lot of values on each method call. When it is really small copying the values and using them directly will be probably faster than copying the pointer and having to grab them from another place.
About restrictions: you can't assign it to null (although you can use Nullable<>) and you have to initialize it right away.
Copying an instance of a struct takes less time than creating a new instance of a class and copying data from an old one, but class instances can be shared and struct instances cannot. Thus, "structvar1 = structvar2" requires copying new struct instance, whereas "classvar1 = classvar2" allows classvar1 and classvar2 refer to the same struct instance (without having to create a new one).
The code to handle the creation of new struct instances is optimized for sizes up to 16 bytes. Larger structs are handled less efficiently. Structs are a win in cases where every variable that holds a struct will hold an independent instance (i.e. there's no reason to expect that any particular two variables will hold identical instances); they are not much of a win (if they're a win at all) in cases where many variables could hold the same instance.

Categories