When you assign an instance of a value type to another instance, the object is copied bit-by-bit to the target location:
private struct Word
{
public Word(char c) { ... }
}
public void Method(Word a)
{
Word b = a; //a is copied and stored in b
}
But given the following code:
private Word _word;
public void Method() {
_word = new Word('x');
}
I suspect that the right-hand side (RHS) expression is evaluated first - which instantiates a value type on the stack - and then the value is copied and stored on the location of the _word field, which is on the heap.
The alternative would be to take the left-hand side into consideration, and instantiate the value type directly on _word, avoiding having to copy the object.
Is my suspicion correct? If it is, I suppose it's safe to assume that the first block of code would perform better than the second.
//1 instantiation + 10k copies
Word[] words = new Word[10000];
Word word = new Word('x');
for (int i = 0; i < 10000; i++)
words[i] = word;
//10k instantiations + 10k copies
Word[] words = new Word[10000];
for (int i = 0; i < 10000; i++)
words[i] = new Word('x');
Note: I'm not trying to micro-optimize anything.
Edit: The core of my question is, as Lee puts it: Are structs allocated in place directly, or do they need to be allocated then copied?
When you assign an instance of a value type to another instance, the object is copied bit-by-bit to the target location
When you assign an instance of a value type to a variable of the same type, the value is copied to the target location, yes. But that is true of reference types as well: the reference is copied bit by bit to the target location. The referent of course stays right where it is.
I suspect that the right-hand side (RHS) expression is evaluated first
The specification states that the left hand side is evaluted to produce a variable, then the right hand side is evaluated to produce a value, and then the assignment happens.
In the examples you give the evaluation of the left hand side does not produce an observable side effect and therefore its evaluation can be re-ordered by the optimizers in the C# compiler, the jitter or the CPU if any of them so choose. But if you had something like
x[i++] = v();
then the side effect on the left hand side has to happen before the call on the right hand side.
The core of my question is: Are structs allocated in place directly, or do they need to be allocated then copied?
The specification states that structures are allocated in a temporary location -- which would typically be the stack or a register in practice -- and then copied to their final destination. However, there are some situations in which the optimizer can determine that it is impossible for the user to notice if the mutation happens "in place" at the final destination. This is a copy elision optimization, and the C# compiler will perform this optimization if it feels it can get away with it.
For more details see my article on the subject:
http://ericlippert.com/2010/10/11/debunking-another-myth-about-value-types/
Are either preferred?
What is the business case for multiple identical structs?
If you need multiple identical objects is a struct the best choice?
A struct (re)initialized in that manner is probably not a good solution for the example use case
In the new array the WordStruct is allocated and initialized using the default ctor (no ctor)
You don't have the option to initialize a struct array with another ctor
If you do need identical structs then this would be preferred
WordStruct[] WordStructS = new WordStruct[1000];
for (int i = 0; i < WordStructS.Length; i++) { WordStructS[i].C = 'x'; }
If multiple identical objects what you really need to do then consider a class
A class new array is allocated but not yet initialized
You don't waste resources initializing with the default constructor
WordClass[] WordClassS = new WordClass[1000];
for (int i = 0; i < WordClassS.Length; i++) { WordClassS[i] = new WordClass('x'); }
If you want to generalize deep copy of an object (struct or class) then consider IConable
In the case of a struct I suspect it is more efficient than a bit wise copy (but I am not positive)
In the case of class it will make a clone (deep copy) not a reference
public struct WordStruct : ICloneable
{
public char C;
public WordStruct(char C)
{
this.C = C;
}
public object Clone()
{
WordStruct newWordStruct = (WordStruct)this.MemberwiseClone();
return newWordStruct;
}
}
I know in a comment you said curiosity but that is not clear in the question
In the question you state first block of code is preferred over the second
I get it is an interesting question of curiosity
But if it is just curiosity then the question should have stopped at
Is my suspicion correct?
Related
In C# I have a VERY huge struct, and I want to iterate through it easily, instead of manually typing them.
I tried using:
Type structType = typeof(myStruct);
System.Reflection.FieldInfo[] fields = structType.GetFields();
for(int i=0; i<fields.Length-1; i++)
{
richTextBox1.Text += fields[i].Name + "\n";
}
where myStruct is the huge struct, but you can't pass variable structs to that, only the structs them selves.
Basically what I want to do is:
public struct myStruct
{
public string myName;
public int myAge;
...
...
}
//in code
myStruct a = readStructFromFile( filename );
string text = "";
foreach(field in a)
{
text += field.name + ": " + file.value;
}
That possible?
Use FieldInfo.GetValue. Bigger structs really should be classes since structs are meant to be small.
myStruct a = readStructFromFile( filename );
Type structType = typeof(myStruct);
System.Reflection.FieldInfo[] fields = structType.GetFields();
var builder = new StringBuilder();
foreach(var field in fields)
{
builder.Append(string.Format("{0} {1}\n",
field.Name,
field.GetValue(a).ToString());
}
richTextBox1.Text += builder.ToString();
My recommendation would be to write some simple code-generation routines to generate something close to the code you want and copy it to the clipboard. Then paste it into your program and make whatever little tweaks are required.
Having to write large amounts of boilerplate code usually implies a design deficiency either in what you're doing or in the language/framework you're using. Depending upon exactly what you're doing, the fault could be in either the former or the latter.
There are situations where large structures are appropriate; if each variable of some type is supposed to encapsulate a fixed collection of independent values, an exposed-field structure expresses that perfectly. Until things start getting so big as to create a risk of stack overflow, the factors which favor using a 4-field structures over a 4-field class will be even more significant with a 20-field structure versus a 20-field class.
There are some definite differences between programming with structures versus programming with classes. If one uses immutable classes, generating from a class instance a new instance which is identical except for a few fields is difficult. If one uses mutable classes, it can be difficult to ensure that every variable encapsulates its own set of independent values. Suppose one has a List<classWithPropertyX> myList, and myList[0] holds an instance where X is 3. One wishes to have myList[0] hold an instance where X is 4, but not affect the value of the X property associated with any other variable or storage location of type classWithPropertyX.
It's possible that the proper approach is
myList[0].X = 4;
but that could have unwanted side-effects. Perhaps one needs to use
myList[0] = myList[0].WithX(4);
or maybe
var temp = myList[0];
myList[0] = new classWithPropertyX(temp.this, 4, temp.that, temp.theOther, etc.);
One may have to examine a lot of code to ascertain with certainty which technique is appropriate. By contrast, if one has a List<structWithExposedFieldX> myList the proper code is:
var temp = myList[0];
temp.X = 4;
myList[0] = temp;
The only information one needs to know that's the correct approach is the fact that structWithExposedFieldX is a struct with an exposed public field X.
I have set my project to accept unsafe code and have the following helper Class to determine the size of an instance:
struct MyStruct
{
public long a;
public long b;
}
public static class CloneHelper
{
public unsafe static void GetSize(BookSetViewModel book)
{
long n = 0;
MyStruct inst;
inst.a = 0;
inst.b = 0;
n = Marshal.SizeOf(inst);
}
}
This works perfectly fine with a struct. However as soon as I use the actual class-instance that is passed in:
public unsafe static void GetSize(BookSetViewModel book)
{
long n = 0;
n = Marshal.SizeOf(book);
}
I get this error:
Type 'BookSetViewModel' cannot be marshaled as an unmanaged structure;
no meaningful size or offset can be computed.
Any idea how I could fix this?
Thanks,
Well, it really depends on what you mean by the "size" of an instance. There's the size of the single object in memory, but you usually need to think about any objects that the root object refers to. That's how much memory may be reclaimable after the root becomes eligible for garbage collection... but you can't just add them up, as those objects may be referred to by multiple other objects, and indeed there may be repeated references even within a single object.
This blog post shows some code I've used before to determine the size of the raw objects (header + fields), disregarding any extra cost due to the objects that one object refers to. It's not something I would use in production code, but it's useful for experimenting with how large an object is under varying circumstances.
I have a List of structure.In the loop i am trying to modify the object's property,which is happening,but when i (Quick look in Visual studio)look into the list object ,the new value is not reflecting.Is it by virtue that the structure's object cannot be modified when in a collection?
I am using generics list with the struct as the type in the list
You mention "modify the object's property" in the context of a struct, but importantly a struct is not an object. Other people have answered as to the issue with structs being copied (and changes discarded), but to take that further the real problem here is that you have a mutable (changeable) struct at all. Unless you are on XNA (or similar) there is simply no need.
If you want to be able to change properties, make it a class:
public class Foo {
public string Bar {get;set;}
}
This is now a reference-type, and your changes (obj.Bar = "abc";) will be preserved through the foreach. If you really want/need a struct, make it immutable:
public struct Foo {
private readonly string bar;
public string Bar { get {return bar; }}
public Foo(string bar) {this.bar = bar;}
}
Now you can't make the mistake of changing the value of a copy; you would instead have to use the indexer to swap the value (list[i] = new Foo("abc");). More verbose (and you can't use foreach), but correct.
But IMO, use a class. Structs are pretty rare, to be honest. If you aren't sure: class.
If you are using a foreach loop you probably got
Compiler Error CS1654
Error Message Cannot modify members of
'variable' because it is a 'read-only
variable type'
This error occurs when you try to
modify members of a variable which is
read-only because it is in a special
construct.
One common area that this occurs is
within foreach loops. It is a
compile-time error to modify the value
of the collection elements. Therefore,
you cannot make any modifications to
elements that are value types,
including structs.
You could however try
struct MyStruct
{
public int i;
}
List<MyStruct> list = new List<MyStruct>
{ new MyStruct { i = 1 }, new MyStruct { i = 2 } };
for(int i = 0; i < list.Count; i++)
{
MyStruct val = list[i];
val.i++;
list[i] = val;
}
EDIT
See also Structs Tutorial
Structs vs. Classes
Structs may seem similar to classes,
but there are important differences
that you should be aware of. First of
all, classes are reference types and
structs are value types.
I THINK i know what the problem might be.
struct Astruct
{
int amember;
}
List < Astruct > listofStructs;
foreach(Astruct A in listofStructs)
{
A.amember = 1337;
}
if this is what you are doing...
when you use structs in c# they are not referenced but copied! so that means the contents of your list is being COPIED to A, so when you change A it doesn't change the value in the list!
to solve this problem (if this is your problem...) either use CLASSES rather than STRUCTS, that way A would be a reference, OR use a manual iterating for loop instead, ie:
for(int i=0;i < listofStructs.Count;i++)
{
listofStructs[i].amember = 1337;
}
alternatively, if you’re using a list, you maybe should use an iterator or something... but the above should definitely fix that problem.
Given the information in your post (although I'd have liked to see the code itself), let me put forth the most probable issue and its fix.
foreach(var s in listOfStructs)
{
s.Property = x;
}
s is assigned to a copy of the actual struct in the collection. s.set_Property is now modifying the copy which is thrown away at the end of the current iteration.
This is because 2 value type variables cannot point to the same instance.
struct1 = new MyStruct(100, 200);
struct2 = struct1; // struct2 is now a copy of struct1
Now to the problem of how do you modify the instances in a collection:
Get the object to modify in a local variable (copy created). Modify it. Now remove the original object and insert the copy. use listOfStructs[i] = modifiedInstance.
I'm getting confused with what happens on the stack and heap in respect to value type properties in classes.
My understanding so far:
When you create a class with a structure (value type) like this:
class Foo
{
private Bar _BarStruct;
public Bar BarStruct
{
get {return _BarStruct; }
set {_BarStruct = value; }
}
}
private struct Bar
{
public int Number;
Bar()
{
Number = 1;
}
Bar(int i)
{
Number = i;
}
}
If you create a class instance like so:
Foo fooObj = new Foo();
The stack and heap will look like this:
...where the Bar structure is embeded in the Foo class in the heap. This makes sense to me, but I start to loose it when we consider modifying the Number integer in the BarStruct class, within the Foo Object. For example:
Foo fooObj = new Foo();
fooObj.BarStruct.Number = 1;
As I understand, this should be returning a copy of BarStruct to live on the stack, which means that any changes of a member of BarStruct would not be carried through to the object, which is why the last line above gives an error.
Is this right so far?
If so, my question is, how come an assignment such as this:
fooObj.BarStruct = new Bar(2);
...is valid and changes the heap value? Surely this is just changing the value on the stack?? Also, (by and by) I find it so confusing that you are able to use new on a value type. To me, new is for allocatting on the heap (as per C++) and feels unnatural to be doing this for items on the stack.
So just to re-iterate the question, Am I correct in my assumption of what happens when a property containing a structure is called and why can you assign a new structure to a copy and yet it still changes the reference on the heap?
Really hope this all make sense.
Yell if you need clarification!
Ta,
Andy.
Looking at this assignment:
fooObj.BarStruct = new Bar(2);
The assignment isn't changing the value on the stack - it's calling the setter for the property.
In other words, whereas your first assignment is equivalent to:
fooObj.get_BarStruct().Number = 1; // Bad
the second is equivalent to:
fooObj.set_BarStruct(new Bar(2));
Does that help?
Note that the problematic assignment becomes a non-issue if you make your value type immutable to start with - which helps in general, in fact. Mutable value types are a really bad idea in C#; you can get into no end of trouble with them.
In terms of your expectations of "new" - try not to think in C++, basically. C# isn't C++, and various things (destructors, generics, behaviour during construction) will confuse you if you try to effectively write C++ in C#. A "new" statement creates a new instance of a type, whether that's a value type or a reference type.
Inside main i declared a local int[] array (int[] nums). I did not pass it by reference.
But when i print values of local array i get squared value of each element.
What is the reason for that?
delegate void tsquare(int[] a);
static void Main()
{
int[] nums = { 1, 2, 3 };
tsquare sqr = new tsquare(SomeClass.Square);
sqr(nums);
foreach (int intvals in nums)
{
Console.WriteLine(intvals);
}
}
class SomeClass
{
public static void Square(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
}
Update:
My appologies to all.What i tought is int[] {Array}is a value type,and the Delegate done
some trick on it.Now from your answer ,i understand Array is Reference type.
There are two concepts here.
Reference types vs. value types
Passing by value vs. passing by reference
Let's tackle the second one first.
Passing something by value means that you give the method its own copy of that value, and it's free to change that value however it wants to, without those changes leaking back into the code that called the method.
For instance, this:
Int32 x = 10;
SomeMethod(x); // pass by value
There's no way x is going to be anything other than 10 after the call returns in this case, since whatever SomeMethod did to its copy of the value, it only did to its own value.
However, passing by reference means that we don't really give the method its own value to play with, rather we give it the location in memory where our own value is located, and thus anything that method does to the value will be reflected back to our code, because in reality, there's only one value in play.
So this:
Int32 x = 10;
SomeMethod(ref x); // pass by reference
In this case, x might hold a different value after SomeMethod returns than it did before it was called.
So that's passing by value vs. passing by reference.
And now to muddle the waters. There's another concept, reference types vs. value types, which many confuses. Your question alludes to you being confused about the issue as well, my apologies if you're not.
A reference type is actually a two-part thing. It's a reference, and it's whatever the reference refers to. Think of a house you know the address of. You writing the address on a piece of paper does not actually put the entire house on that paper, rather you have a "reference" to that particular house on your piece of paper.
A reference type in .NET is the same thing. Somewhere in memory there is an object, which is a set of values, grouped together. The address of this object you store in a variable. This variable is declared to be a type which is a reference type, which allows this two-part deal.
The nice thing about reference types is that you might have many references to the same actual object, so even if you copy the reference around, you still only have one object in memory.
Edit: In respect to the question, an array is a reference type. This means that your variable only holds the address of the actual array, and that array object is located somewhere else in memory.
A value type, however, is one thing, the entire value is part of the "value type", and when you make copies of that, you make distinct copies
Here's an example of value types:
struct SomeType
{
public Int32 Value;
}
SomeType x = new SomeType;
x.Value = 10;
SomeType y = x; // value type, so y is now a copy of x
y.Value = 20; // x.Value is still 10
However, with a reference type, you're not making a copy of the object it refers to, only the reference to it. Think of it like copying the address of that house onto a second piece of paper. You still only have one house.
So, by simply changing the type of SomeType to be a reference type (changing struct to class):
class SomeType
{
public Int32 Value;
}
SomeType x = new SomeType;
x.Value = 10;
SomeType y = x; // reference type, so y now refers to the same object x refers to
y.Value = 20; // now x.Value is also 20, since x and y refer to the same object
And now for the final thing; passing a reference type by value.
Take this method:
public void Test(SomeType t)
{
t.Value = 25;
}
Given our class-version of SomeType above, what we have here is a method that takes a reference type parameter, but it takes it as being passed by value.
What that means is that Test cannot change t to refer to another object altogether, and make that change leak back into the calling code. Think of this as calling a friend, and giving him the address you have on your piece of paper. No matter what your friend is doing to that house, the address you have on your paper won't change.
But, that method is free to modify the contents of the object being referred to. In that house/friend scenario, your friend is free to go and visit that house, and rearrange the furniture. Since there is only one house in play, if you go to that house after he has rearranged it, you'll see his changes.
If you change the method to pass the reference type by reference, not only is that method free to rearrange the contents of the object being referred to, but the method is also free to replace the object with an altogether new object, and have that change reflect back into the calling code. Basically, your friend can tell you back "From now on, use this new address I'll read to you instead of the old one, and forget the old one altogether".
The array reference is passed by value automatically because it is a reference type.
Read:
Reference Types
Value Types
Most of the other answers are correct but I believe the terminology is confusing and warrants explanation. By default, you can say that all parameters in C# are passed by value, meaning the contents of the variable are copied to the method variable. This is intuitive with variables of value types, but the trick is in remembering that variables that are reference types (including arrays) are actually pointers. The memory location the pointer contains is copied to the method when it is passed in.
When you apply the ref modifier, the method gets the actual variable from the caller. For the most part the behavior is the same, but consider the following:
public void DoesNothing(int[] nums)
{
nums = new []{1, 2, 3, 4};
}
In DoesNothing, we instantiate a new int array and assign it to nums. When the method exits, the assignment is not seen by the caller, because the method was manipulating a copy of the reference (pointer) that was passed in.
public void DoesSomething(ref int[] nums)
{
nums = new []{1, 2, 3, 4};
}
With the ref keyword, the method can essentially reach out and affect the original variable itself from the caller.
To achieve what you seemed to originally want, you could create a new array and return it, or use Array.CopyTo() in the caller.
In C#, all parameters are passed by value by default. There are two kinds of types in C#, namely value and reference types.
A variable of reference type when passed as a parameter to a function will still be passed by value; that is if the function changes the object referred to by that variable, after the function completes the variable that was passed in will still refer to the same object (including null) as it did prior to calling the function in the same context.
However, if you use the ref modifier when declaring the function parameter than the function may change the object being referenced by the variable in the caller's context.
For Value types this is more straightforward but it is the same concept. Bear in mind, int[] is a reference type (as are all arrays).
Consider the differences in these functions when passing in some some array of ints:
public static void Square1(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
public static void Square2(int[] array)
{
array = {10, 20, 30};
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
public static void Square3(ref int[] array)
{
array = {10, 20, 30};
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
You're not passing it by reference. The array is being passed in by value, but arrays in .NET are reference types, so you're passing in a reference to the array, which is why you're seeing the values squared.
Read the following SO question - it explains the differences between pass-by-value and pass-by-reference. The accepted answer has a link in it to a good article about the topic that should help you understand the difference.
what is different between Passing by value and Passing by reference using C#
Arrays are objects and are passed by reference. Ints are structs and are passed by value (unless you use the ref keyword in your method signature as per the picky guy in the comments) (who was right) (but picky).