Whenever I tried to search about differences between classes and structs in C# or .net, I ended up with the conceptual overview of the two things like value type or the reference type, where the variables are allocated etc. But I need some practical differences. I have found some like different behavior of assignment operator, having constructors etc. Can anybody provide some more practical differences which will be directly useful while coding? Like the things works with one but not with other or same operation showing different behavior. And some common mistakes regarding these two.
Also please suggest where to consider using a struct instead of a class. And where the structs should not be used.
Edit:
Do I have to call the constructor explicitly or just declaring a struct type variable will suffice?(Should I make it a new question?)
OK, here are a few specific, practical differences:
A variable can be null if it’s a class, but is never null if it’s a struct.
default(T) is null for a class, but for a struct actually constructs a value (consisting of lots of binary zeros).
A struct can be made nullable by using Nullable<T> or T?. A class cannot be used for the T in Nullable<T> or T?.
A struct always has a public default constructor (a constructor with zero parameters). The programmer cannot override this constructor with a custom implementation — it is basically “set in stone”. A class allows the programmer to have no default constructor (or a private one).
The fields in a class can have default values declared on them. In a struct they can’t.
A class can inherit from another class, but a struct cannot be declared to derive from anything (it implicitly derives from System.ValueType).
It makes sense to use a class in object.ReferenceEquals(), but using a struct variable will always yield false.
It makes sense to use a class in a lock() statement, but using a struct variable will cause very subtle failure. The code will not be locked.
On a 32-bit system, you can theoretically allocate an array of up to 536,870,912 references to a class, but for a struct you need to take the size of the struct into account because you are allocating actual instances.
Structs in a container can only be modified if the container is a built-in array:
struct Point { public int x, y; void Move(int dx, int dy) { x += dx; y += dy; } }
...
Point[] points = getPointsArray();
points[0].Move(10, 0) = 10;
// points[0].x is now 10 higher.
List<Point> points = getPointsList();
points[0].Move(10, 0);
// No error, but points[0].x hasn't changed.
For this reason, I strongly favour immutable structs:
Point Move(int dx, int dy) { return new Point(x + dx, y + dy); }
...
points[0] = points[0].Move(10, 0); // Always works.
General observation: classes are usually better. Structs excel when you want to hold small, conceptually atomic data structures such as Point, Complex (number), Rational, etc.
structs, as they are value types, are copied on assignment; if you create your own struct, you should make it immutable, see Why are mutable structs evil?
Sometimes you don't want what you're passing to be mutable, and since a mutable struct may just be pure evil, I'd steer clear of ever creating one :) Here's an example a situation:
class Version:
class AccountInfo {
public string OwnerName { get; set; }
public string AccountNumber { get; set; }
}
struct Version:
struct AccountInfo {
public string OwnerName;
public string AccountNumber;
}
Now picture you called a method like this:
public bool TransferMoney(AccountInfo from, AccountInfo to, decimal amount)
{
if(!IsAuthorized(from)) return false;
//Transfer money
}
A struct is a Value type, meaning a copy gets passed into the method. The class version means a reference gets passed into the method, you wouldn't want for example the account number to be changeable after the authorization passed, you want nothing to be changed in an operation like this...you want an immutable value type. There's another question here asking why mutable structs are evil...any operation where you wouldn't want anything affected by the reference object changing, would be a practical place where a struct may fit better.
The example above may be somewhat silly, but the point is any sensitive operation where the passed in data shouldn't change in another thread or by any means really would be a place you look at passing by value.
Where they are allocated (heap vs. stack) is not something you really care about while you use them (not that you should disregard this - you should by all means study the differences and understand them).
But the most important practical difference you will come across the first time you decide to replace your class with a struct, is that structs are passed by value, while class instances are passed by reference.
This means that when you pass a struct to a method, a copy of its properties is created (a shallow copy) and your method actually gets a different copy than the one you had outside the method. When you pass an instance of a class, only a reference to the same place in memory is passed to the method, and your method is then dealing with exactly the same data.
For example, if you have a struct named MyStruct, and a class named MyClass, and you pass them to this method:
void DoSomething(MyStruct str, MyClass cls)
{
// this will change the copy of str, but changes
// will not be made to the outside struct
str.Something = str.Something + 1;
// this will change the actual class outside
// the method, because cls points to the
// same instance in memory
cls.Something = cls.Something + 1;
}
when the method ends, your class' property will be incremented, but your struct's property will remain unchanged, because str variable inside the DoSomething method does not point to the same place in memory.
The singularly important practical difference is that structs are value types, whereas classes are reference types. That has a few implications.
First of all, structs are copied on assignment. These two code blocks will have a different result (please note, normally you should neither use public fields nor mutable structs, I'm doing this for demonstration purposes only):
struct X
{
public int ID;
public string Name;
}
X x1 = new X { ID = 1, Name = "Foo" };
X x2 = x1;
x2.Name = "Bar";
Console.WriteLine(x1.Name); // Will print "Foo"
class Y
{
public int ID;
public string Name;
}
Y y1 = new Y { ID = 2, Name = "Bar" };
Y y2 = y1;
y2.Name = "Baz";
Console.WriteLine(y1.Name); // Will print "Baz"
X and Y are exactly the same, except that X is a struct. The results of this are different because every time we assign an X, a copy is made, and if we change the copy then we aren't changing the original. On the other hand, when we assign the contents of y1 to y2, all we've done is copied a reference; both y1 and y2 refer to physically the same object in memory.
The second consequence of structs being value types is generic constraints. If you want to pass in value types, the name of the constraint is literally "struct" or "class":
public class MyGeneric<T>
where T : struct
{ ... }
The above will let you create a MyGeneric<int> or MyGeneric<X>, but not a MyGeneric<Y>. On the other hand, if we change it to where T : struct, we're no longer allowed to create either of the first two, but MyGeneric<Y> is okay.
Last but not least, you need to use structs when writing interop, because with structs you're able to guarantee a specific arrangement in memory.
The link Tejs provided (http://www.jaggersoft.com/pubs/StructsVsClasses.htm) is a good explanation (although it is a bit out of date, particularly on the explanation of events).
The most import practical difference is that a struct is a value type, meaning it is passed by value rather than by reference. What this really means is that when a struct is passed as an argument, it is actually passed by copy. As a result, operations on one instance of a struct do not affect other instances.
Consider the following code:
struct NumberStruct
{
public int Value;
}
class NumberClass
{
public int Value = 0;
}
class Test
{
static void Main()
{
NumberStruct ns1 = new NumberStruct();
NumberStruct ns2 = ns1;
ns2.Value = 42;
NumberClass nc1 = new NumberClass();
NumberClass nc2 = nc1;
nc2.Value = 42;
Console.WriteLine("Struct: {0}, {1}", ns1.Value, ns2.Value);
Console.WriteLine("Class: {0}, {1}", nc1.Value, nc2.Value);
}
}
Because both ns1 and ns2 are of the NumberStruct value type, they each have their own storage location, so the assignment of ns2.Number does not affect the value of ns1.Number. However, because nc1 and nc2 are both reference types, the assignment of nc2.Number does affect the value of nc1.Number because they both contain the same reference.
[Disclaimer: The above code and text taken from Sams Teach Yourself Visual C# 2010 in 24 Hours]
Also, as others have already pointed out, structs should always be immutable. (Yes, in this example the struct is mutable but it was to illustrate the point.) Part of that means that structs should not contain public fields.
Since structs are value types, you cannot inherit from a struct. You also cannot derive a struct from a base class. (A struct can implement interfaces, however.)
A struct is also not allowed to have an explicitly declared public default (parameterless) contstructor. Any additional constructors you declare must completely initialize all of the struct fields. Structs also cannot have an explicitly declared destructor.
Since structs are value types, they shouldn't implement IDisposable and shouldn't contain unmanaged code.
Here's an interesting link: http://www.jaggersoft.com/pubs/StructsVsClasses.htm
For the most part though, there isn't much of a compelling reason to use structs when classes offer far more to the developer.
Related
I started my journey with C# but I realised that I have some problems with some basic information about memory when it comes to declaration of variables. See if I am correct.
int x; // I declared variable of type int, which name is x. Compiler will provide memory for it but we dont have known value of it.
x=10; // Now memory location is still the same but value now kept there is 10;
public struct Point {
public int x, y;
}
Now I define a struct named Point. Beacuse struct is a value type, it again has reserved memory for it on the computer. Howewer x and y have no value.
Now Point p1 = new Point(); // what is happening here? Struct is not a reference type. So is this just initialization of Point variable with the default constructor without assigning values to x and y?
Second short question. When I write a code like:
int x = 10;
Can I say that I created instance of class integer which value is 10 and name x;
I would be grateful for help.
// what is happening here? Struct is not a reference type. So is this just initialization of Point variable with the default constructor without assigning values to x and y?
No; there are 4 possible scenarios here:
a class: the memory space is wiped to all 0s, then any custom constructor is invoked, which may also involve field initializers
a struct called without a custom constructor: the memory space is wiped to all 0s
a struct called with a custom constructor: the custom constructor is required to assign all the fields
a struct variable used without ever calling a constructor: this is actually a thing, but the calling code must write to all the fields before they can do anything else with it; since most structs do not expose their fields, this rarely works
Second short question. When i write a code like:
int x = 10;
Can i say that i created instance of class integer which value is 10 and name x; I would be grateful for help.
Not really, because in C# terms, int is not a class (it might be in IL terms). Simply: you have declared a local variable of type int with name x and assigned it the value 10, if this is in a method. If this is a class field, then: you have declared a private instance field of type int named x with a field-initializer giving it the value of 10.
Incidentally, you should avoid public fields in general, and mutable fields on structs. You might prefer:
public struct Point {
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y) { this.x = x; this.y = y'; }
}
This will avoid a huge range of problems.
In C# the default struct constructor sets the struct memory to 0, effectively setting all variables to their default values.
In case of ints, it will be 0. For reference types, it will result in null.
(in other words, for any type T it will be default(T)).
Note that when you write a custom constructor in a struct, you must initialize all member fields.
When you write
int x;
this is similar to
Point p1 = new Point(); (considering Point structure is already defined)
in both the cases all integer variables will have default value of 0 and not null, which is is basically what is used in C# to denote 'nothing' and can be assigned only to reference types.
As well, in c# everything is a class, so when you write
int x = 10;
you are creating an instance of class Int32, though the run time will handle this as value type instead of ref type, as special case.
Same is true for other basic types like, Long, DateTime and few others
I have a class named ACTIVITY. This class contains a list of Laps, and each Lap has a collection of TRACPOINTS.
ACTIVITY --many--> LAPS ---many --> TRACPOINTS.
Whenever I fLatten the TRACPOINTS collection I get the list of all the TRACPOINTS. But when I modify those of course the originals don't get modified since it's a copy.
Is there any way that whatever change I made to the flattened tracpoints gets changed in the Tracpoints list for each lap?
As long as TRACPOINT is a struct, it is not possible in any reasonable way.
Whenever you assign a value of struct variable or field to another variable or field, its contents are copied. The same holds for passing it as a method argument or returning it from a method, its value is copied. This is value semantics [1]. Compare this to atomic types like int, which have value semantics too. You would probably expect the following code to print 2, not 3.
static function Change(int j) { j = 3; }
static void Main(string[] args) {
int i = 2;
Change(i);
System.Console.WriteLine(i);
}
If you do SelectMany, each value from the collection is probably assigned to some temporary local variable and then returned from the iterator (SelectMany), therefore it is copied and in fact possibly copied many times before it comes out from the iterator. So what you are updating is a copy of the struct. Like in the example, you're not changing variable i, but its copy stored in variable j.
This is why structs should be immutable. Instead of having properties with getters and setter in your struct, they should have only getters. For changing values of properties of a struct, you can implement methods that copy the whole original struct, change the value of the desired property and return the new struct instance. In fact, again, its copy will be returned. Example:
struct S {
int f;
public int F { get { return this.f; } }
public S SetF(int newVal) {
var s = new S();
s.f = newVal;
return s;
}
}
var x = new S();
x = x.SetF(30);
That said, it could be possible to achieve what you want with pointers and unsafe C#, but believe me, it will be way easier to change your structs to classes, so that they have reference semantics instead of value semantics, or keep them structs, but make them immutable and do not use Linq, but old school loops. If you want to use Linq for something like SelectMany in such scenario, you probably do not care about performance difference between structs and classes so much...
[1] http://msdn.microsoft.com/en-us/library/aa664472(v=vs.71).aspx
classes deal with the reference types and traditional data types deal with the value type just for example :
int i=5;
int j=i;
i=3 ; //then this will output i=3 and j=5 because they are in the different memory blocks .
Similarly if we talk about the object of a class say point class
class point
{
public int x,y;
void somefucnt(point p,int x)
{
Console.writeline("value of x is "+p.x);
x=22;
Console.writeline("value of x is "+p.x);
}
}
class someotherclass
{
static void Main(string [] args )
{
p1.x=10;
p1.somefunct(p1,p1.x);
}
}
Both console.write statements are printing 10 , despite ive changed x to some other value ? why is it so ?since p is just the reference to x so it should be updated by changing values of x . this thing is really confusing me alot .
The observed behavior has nothing to do with Value types vs Reference types - it has to do with the Evaluation of Strategy (or "calling conventions") when invoking a method.
Without ref/out, C# is always Call by Value1, which means re-assignments to parameters do not affect the caller bindings. As such, the re-assignment to the x parameter is independent of the argument value (or source of such value) - it doesn't matter if it's a Value type or a Reference type.
See Reference type still needs pass by ref? (on why caller does not see parameter re-assignment):
Everything is passed by value in C#. However, when you pass a reference type, the reference itself is being passed by value, i.e., a copy of the original reference is passed. So, you can change the state of object that the reference copy points to, but if you assign a new value to the reference [parameter] you are only changing what the [local variable] copy points to, not the original reference [in the argument expression].
And Passing reference type in C# (on why ref is not needed to mutate Reference types)
I.e. the address of the object is passed by value, but the address to the object and the object is the same. So when you call your method, the VM copies the reference; you're just changing a copy.
1 For references types, the phrasing "Call By Value [of the Reference]" or "Call by [Reference] Value" may help clear up the issue. Eric Lippert has written a popular article The Truth about Value Types which encourages treating reference values as a distinct concept from References (or instances of Reference types).
void somefucnt(point p,int x){
Console.writeline("value of x is "+p.x);
x=22;
Console.writeline("value of x is "+p.x);
}
Here, the x=22 won´t change p.x but the parameter x of (point p,int x)
Normally, your assumtion about values/references is ok (if I understood it correctly).
Tip: Google for c# this instead of passing a object to it´s own method
You change the value of the parameter (x), not the value of p.x, value types are passed by value unless you use the ref keyword.
Like in your first example, there is no relationship between i and j as well as the parameter x, and p1.x.Each variable has it's own space in the memory.So changing one of them doesn't affect to the other.
You have two different variables named x in the somefucnt function. One is the member variable x which you are trying to change, the other is the function input parameter in void somefucnt(point p, int x). When you say x = 22, the input parameter x is changed instead of the member variable x.
If you change the line x = 22 to this.x = 22 then it should work as you expect.
Side note:
A good practice to avoid confusion is to always have class members private and name them as _x. Otherwise, have public auto properties in CamelCase, like this:
public int X { get; set; }
These methods avoid ambiguity between class variables and function input variables.
I am building internal logic for a game in C# and coming from C++ this is something that might be lost in translation for me.
I have an object, Ability that calculates the bonus it provides and returns that as an integer value. The calculation is meant to be dynamic and can change depending on a variety of variables.
public class Ability: Buffable
{
public string abbr { get; private set; }
public Ability(string name, string abbr, uint score) : base(name, score)
{
this.abbr = abbr;
}
// Ability Modifier
// returns the ability modifier for the class.
public int Ability_modifier()
{
const double ARBITARY_MINUS_TEN = -10;
const double HALVE = 2;
double value = (double)this.Evaluate();
double result = (value + ARBITARY_MINUS_TEN) / HALVE;
// Round down in case of odd negative modifier
if (result < 0 && ((value % 2) != 0))
{
result--;
}
return (int)result;
}
I then have another object, Skill which should be aware of that bonus and add it into it's calculation. I wanted to pass an Ability into the constructor of Skill by reference and then store that reference so that if the Ability changed the calculation would as well. The obvious problem with this being that apparently storing references is taboo in C#.
Is there either a work around way to do this or an alternate way to approach this problem that my pointer infested mind isn't considering? I would greatly prefer not to have to pass the ability to the function that evaluates Skill every time, since the one referenced never changes after construction.
The obvious problem with this being that apparently storing references is taboo in C#.
Absolutely not. References are stored all over the place. You're doing it here, for example:
this.abbr = abbr;
System.String is a class, and therefore a reference type. And so the value of abbr is a reference.
I strongly suspect you've misunderstood how reference types work in C#. If you remember a reference to an object, then changes to the object will be visible via the reference. However, changes to the original expression you copied won't be.
For example, using StringBuilder as a handy mutable reference type:
StringBuilder x = new StringBuilder("abc");
// Copy the reference...
StringBuilder y = x;
// This changes data within the object that x's value refers to
x.Append("def");
// This changes the value of x to refer to a different StringBuilder
x = new StringBuilder("ghi");
Console.WriteLine(y); // abcdef
See my articles on references and values, and parameter passing in C# for much more detail.
I am not quite seing enough of your code to give a concrete example, but the way to do this is to pass in a lambda delegate such as () => object.property instead of this: object.property.
In C#, there are reference types and value types. All non-value-type objects are passed by reference, so there should be no issue with references. Just pass it, and it will be passed by reference.
This is a simplified version of some of my code:
public struct info
{
public float a, b;
public info? c;
public info(float a, float b, info? c = null)
{
this.a = a;
this.b = b;
this.c = c;
}
}
The problem is the error Struct member 'info' causes a cycle in the struct layout. I'm after struct like value type behaviour. I could simulate this using a class and a clone member function, but I don't see why I should need to.
How is this error true? Recursion could perhaps cause construction forever in some similar situations, but I can't think of any way that it could in this case. Below are examples that ought to be fine if the program would compile.
new info(1, 2);
new info(1, 2, null);
new info(1, 2, new info(3, 4));
edit:
The solution I used was to make "info" a class instead of a struct and giving it a member function to returned a copy that I used when passing it. In effect simulating the same behaviour as a struct but with a class.
I also created the following question while looking for an answer.
Value type class definition in C#?
It's not legal to have a struct that contains itself as a member. This is because a struct has fixed size, and it must be at least as large as the sum of the sizes of each of its members. Your type would have to have 8 bytes for the two floats, at least one byte to show whether or not info is null, plus the size of another info. This gives the following inequality:
size of info >= 4 + 4 + 1 + size of info
This is obviously impossible as it would require your type to be infinitely large.
You have to use a reference type (i.e. class). You can make your class immutable and override Equals and GetHashCode to give value-like behaviour, similar to the String class.
The reason why this creates a cycle is that Nullable<T> is itself a struct. Because it refers back to info you have a cycle in the layout (info has a field of Nullable<info> and it has a field of info) . It's essentially equivalent to the following
public struct MyNullable<T> {
public T value;
public bool hasValue;
}
struct info {
public float a, b;
public MyNullable<info> next;
}
The real problem is on this line:
public info? c;
Since this is a struct, C# needs to know the inner info/s layout before it could produce outer info's layout. And the inner info includes an inner inner info, which in turn includes an inner inner inner info, and so on. The compiler cannot produce a layout because of this circular reference issue.
Note: info? c is a shorthand for Nullable<info> which is itself a struct.
There isn't any way to achieve mutable value semantics of variable-sized items (semantically, I think what you're after is to have MyInfo1 = MyInfo2 generate a new linked list which is detached from the one started by MyInfo2). One could replace the info? with an info[] (which would always either be null or else populated with a single-element array), or with a holder class that wraps an instance of info, but the semantics would probably not be what you're after. Following MyInfo1 = MyInfo2, changes to MyInfo1.a would not affect MyInfo2.a, nor would changes to MyInfo1.c affect MyInfo2.c, but changes to MyInfo1.c[0].a would affect MyInfo2.c[0].a.
It would be nice if a future version of .net could have some concept of "value references", so that copying a struct wouldn't simply copy all of its fields. There is some value to the fact that .net does not support all the intricacies of C++ copy constructors, but there would also be value in allowing storage locations of type 'struct' to have an identity which would be associated with the storage location rather than its content.
Given that .net does not presently support any such concept, however, if you want info to be mutable, you're going to have to either put up with mutable reference semantics (including protective cloning) or with weird and wacky struct-class-hybrid semantics. One suggestion I would have if performance is a concern would be to have an abstract InfoBase class with descendants MutableInfo and ImmutableInfo, and with the following members:
AsNewFullyMutable -- Public instance -- Returns a new MutableInfo object, with data copied from the original, calling AsNewFullyMutable on any nested references.
AsNewMutable -- Public instance -- Returns a new MutableInfo object, with data copied from the original, calling AsImmutable on any nested references.
AsNewImmutable -- Protected instance -- Returns a new ImmutableInfo object, with data copied from the orignal, calling AsImmutable (not AsNewImmutable) on any nested references.
AsImmutable -- Public virtual -- For an ImmutableInfo, return itself; for a MutableInfo, call AsNewImmutable on itself.
AsMutable -- Public virtual -- For a MutableInfo, return itself; for an ImmutableInfo, call AsNewMutable on itself.
When cloning an object, depending upon whether one expected that the object or its descendants would be cloned again before it had to be mutated, one would call either AsImmutable, AsNewFullyMutable, or AsNewMutable. In scenarios where one would expect an object to be repeatedly defensively cloned, the object would be replaced by an immutable instance which would then no longer have to be cloned until there was a desire to mutate it.
Disclaimer: This may not achieve the goal of "struct like value type behaviour."
One solution is to use an array of one item to essentially get a reference the recursively referenced structure. Adapting my approach to your code looks something like this.
public struct info
{
public float a, b;
public info? c
{
get
{
return cArray[nextIndex];
}
set
{
steps[nextIndex] = value;
}
}
private info?[] cArray;
public info(float a, float b, info? c = null)
{
this.a = a;
this.b = b;
this.cArray = new info?[] { c }
this.c = c;
}
}