Value types fields are reference types? - c#

I am a bit confused here. With structs, I cannot directly change its fields as the whole struct is of the value type.
But what about classes with value type fields? If I have a public field int X, I can modify it properly. So the only manifestation of value-type nature of its field would be that when passed as an argument, it is a copy?
EDIT: Also
Class A
{
int B=100; //this is a field, so reference type. But it is a value type.
}
The address to content of B is stored on the heap, but is the value of B stored on the stack?

With structs, I cannot directly change its fields as the whole struct is of the value type.
You cannot change fields in situations when C# makes a copy of the struct for you. In other situations, you can modify fields of a struct. Here is a small demonstration of the difference:
struct Foo {
public int A {get;set;}
public void SetA(int a) {
A = a;
}
}
class Bar {
Foo f;
public Foo F {
get{return f;}
set {f = value;}
}
public void SetFooA(int x) {
f.SetA(x);
}
}
public static void Main() {
Bar b = new Bar();
b.F.SetA(123); // b.F makes a copy, so changing A fails
Console.WriteLine("{0}", b.F.A);
b.SetFooA(456); // Inside Bar, f.SetA is called directly, so the change works fine
Console.WriteLine("{0}", b.F.A);
b.F = new Foo { A = 112233 }; // This also works, because the whole F is assigned
Console.WriteLine("{0}", b.F.A);
}
If I have a public field int X, I can modify it properly.
The same rule applies to user-defined structs, as long as you modify the whole of it. You can't modify part of an int, because it is not a composite. Modification of a struct works fine when you assign the whole struct at once. In other words, assigning
b.F = new Foo { A = 112233 };
in my example replaces assigning
B = 100;
in your example.
Demo.

The address to content of B is stored on the heap, but is the value of B stored on the stack?
No. Value type fields of a class are stored on the heap.
Please refer to #Marc Gravell's answer here for more information about this:
Why value-types are stored onto Stacks?
You may also want to read #Eric Lippert's blog post on the subject: https://blogs.msdn.microsoft.com/ericlippert/2010/09/30/the-truth-about-value-types/
In short value types can be stored on the stack but they are not always stored on the stack.

Struct gives you a copy of the original field because a copy of the struct would be passed. Changing it to class would pass a reference to the class and therefore the field would modify if you were to change it.

Related

Store a ref value in C# [duplicate]

In C#, is there a way to keep a reference as a member variable in an object (like an object pointer in C++), not just as a parameter?
EDIT: How can I make a pointer or reference to an object as a member variable?
No. Don't forget that the argument could reference a local variable which is out of scope by the time you use the object later on. A couple of options:
Use a mutable wrapper type
Use a delegate which captures the variable instead
Redesign your code to not require this in the first place
It's hard to know which is most suitable without knowing more about what you're trying to achieve, but ref is a dead-end.
If you mean ref the argument passing convention, then no, you cannot store this. From the first note on MSDN:
Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same...
Edit: based on your updated question, C# has different nomenclature about pointers and references. A pointer in C# is an unsafe construct used to somewhat directly reference the memory location of an object. I say somewhat because the memory location can change based on garbage collection (unless you fix it in memory).
References in C# are the default way reference types are passed and stored. They are akin to pointers in other languages, but not quite the same. However, the by-reference argument passing convention allows you to directly change what an object refers to.
If your objective is to keep a mutable reference to a non-reference type local variable, you'll have to encapsulate the local variable in a reference type (like a class). If you could give some sample code, we can give some specific examples.
Yes if it is a reference-type instance. And then it is the only way to store it in another class:
class Bar { }
class Foo
{
private Bar b; // b is a reference to a Bar
}
No if it's about a value-type, or a reference to a reference.
You would see simple object-references everywhere that C++ uses pointers, like in building Trees or Linked-Lists.
class Element { ...; private Element _next; }
For what its worth, you could use an array of size 1 as a reference/pointer. This yields more readable code than creating a new class to wrap a single value type member.
public struct StructWithReferenceMember
{
private int[] intStoredAsReference;
public StructWithReferenceMember(int asValue, int asReference)
: this()
{
IntStoredAsValue = asValue;
intStoredAsReference = new int[] { asReference };
}
public int IntStoredAsValue { get; set; }
public int IntStoredAsReference
{
get { return intStoredAsReference[0]; }
set { intStoredAsReference[0] = value; }
}
}
A similar trick can be used to attempt the highly discouraged practice of using mutable structs.
public class ReferenceProperty<T>
{
private T[] typeReference;
public ReferenceProperty(T value)
{
typeReference = new T[] { value };
}
public T PropertyAsValue
{
get { return typeReference[0]; }
set { typeReference[0] = value; }
}
public T[] PropertyAsReference
{
get { return typeReference; }
}
}
Then use array notation to "dereference" it.
public struct MutableStruct
{
public int member;
public MutableStruct(int value)
{
member = value;
}
}
ReferenceProperty<MutableStruct> referenceToValueType = new ReferenceProperty<MutableStruct>(new MutableStruct(3));
Console.WriteLine("original value: " + referenceToValueType.PropertyAsValue.member.ToString());
//referenceToValueType.PropertyAsValue.member = 4; // compiler error - cannot modify return value because it is not a variable
MutableStruct copyOfStruct = referenceToValueType.PropertyAsReference[0]; // or referenceToValueType.PropertyAsValue
copyOfStruct.member = 4;
Console.WriteLine("original value after modifying copy: " + referenceToValueType.PropertyAsValue.member.ToString());
referenceToValueType.PropertyAsReference[0].member = 5;
Console.WriteLine("original value after modifying reference: " + referenceToValueType.PropertyAsValue.member.ToString());
original value: 3
original value after modifying copy: 3
original value after modifying reference: 5
The way to get the address of a variable is the & operator, similar to C++. Again similarly to C++, you can store the address as a pointer:
class Foo
{
object* _objPtr;
Foo(object obj)
{
unsafe
{
_objPtr = &obj;
}
}
}
Note that any code that uses the address-of operator (&) or pointers must be within a method marked unsafe or within an unsafe code block.
This could be useful if you want to increase performance by not doing array bound-checking for example. The downside (besides safety considerations) is that the assembly must be fully-trusted for it to execute.
As pointed out, in C#, you very rarely actually store pointers, instead you store references so the garbage collector can operate properly. Ensure that you really need pointers in your code before using them!
For more info, see: http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx

Strange behavior of Struct in C#

I have a structure as below. I have few problems
Problem1:
struct MyStruct
{
public MyStruct(int a)
{
this.a = a;
this.b = 10;
}
public int a;
public int b;
}
When I remove this.b from MyStruct constuctor it will give me an error "Field must be fully assigned before control is returned to the caller". but in case of class it doesn't occur
Problem2:
struct MyStruct
{
//public MyStruct(int a)
//{
// this.a = a;
// this.b = 10;
//}
//int asd;
//public int MyProperty { get; set; }
public void getImplemen()
{
Console.WriteLine("azsdfa");
}
public int a;
public int b;
}
static void Main(string[] args)
{
MyStruct myStruct ;
myStruct.a = 15;//when I comment this it will give an error
myStruct.b = 15; //when I comment this it will give an error
myStruct.getImplemen();
}
When I change MyStruct myStruct to MyStruct myStruct = new MyStruct ();
it works fine.
why so?
That's just how it goes.
Default constructor initializes every field to a default value, while a constructor with parameters forces you to initialize every field in the struct.
What if you have a default constructor AND one with parameters, you ask? Well, I don't remember. Easy enough to check on your own.
It does not allocate memory for fields:
MyStruct myStruct;
Allocates memory and initialize fields in constructor:
MyStruct myStruct = new MyStruct();
If you does not allocate memory for a variable then you can not assign a value to the fields. Сonstructor allocate memory and initializes fields (you need initialize fields in constructor before control is returned to the caller).
you should refer to https://msdn.microsoft.com/en-us/library/aa288471(v=vs.71).aspx
you need to create the instance of your struct before using it.
The difference is that structs are value types while classes are reference types. When a value type object is created, memory space will be allocated to store the value, thus its member variable cannot be null, whilst class member variables can be null. Hence, the compiler only complains when struct member variables are not assigned to.
Remember the thumb rule for Structs: All fields must be initialized. Values can be provided by you or default ones.
For Question 1:
When you initialize struct with 'new' (without parameters), all fields in it are initialized to default type values (0 for int, null for string etc). Since you are using parameterized constructor compiler does not use default one and hence you get error if you don't initialize field 'b'. You can still make this work as below:
public MyStruct(int a) : this()
{
this.a = a;
}
For Question 2:
Recall the thumb rule I mentioned in the beginning. So you either use default constructor with 'new' initialization or set field values in calling code.
Quick suggestion: Please do not use public fields in class/struct. Use properties to encapsulate them.

How do I convert to c# - passing a struct in C to a function?

In C I have this function:
void(MyStruct* ms){
ms->Prop1 = 2;
ms->Prop2 = 3;
}
With Struct
struct{
int Prop1;
int Prop2;
}MyStruct;
What is the equivalent of this in C#?
What I'm not sure about its two things:
In C# do I use a Struct or Class? Because I thought in C# structs are only value types.
Do I pass the struct or class with ref keyword?
As the code in C says *(a pointer to variable) you can use ref in C#. Also you can stick with struct unless you have any method implementations in that.
class is probably what you're looking for as in your example code you're passing around pointers and modifying the instance.
For more information see the MSDN Documentation:
A class is a reference type. When an object of the class is created, the variable to which the object is assigned holds only a reference to that memory. When the object reference is assigned to a new variable, the new variable refers to the original object. Changes made through one variable are reflected in the other variable because they both refer to the same data.
A struct is a value type. When a struct is created, the variable to which the struct is assigned holds the struct's actual data. When the struct is assigned to a new variable, it is copied. The new variable and the original variable therefore contain two separate copies of the same data. Changes made to one copy do not affect the other copy.
In general, classes are used to model more complex behavior, or data that is intended to be modified after a class object is created. Structs are best suited for small data structures that contain primarily data that is not intended to be modified after the struct is created.
As a class this could be represented simply as:
public class MyClass
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
And passed to a function as:
public void Test(MyClass s)
{
s.Prop1 = 2;
s.Prop2 = 3;
}
With no need for ref

passing objects as parameters

The application is printing 24 but shouldn't it be printing 18 when we know that without ref keyword only a copy of object is passed and no change is made to the original object.
I have created a class called myclass and an object me. age is a public variable in class myclass.
I have set me.age as 18 and through the method show I have changed it to 24.
class Program
{
static void Main(string[] args)
{
myclass me = new myclass();
me.age = 18;
show(me);
Console.WriteLine(me.age);
Console.ReadLine();
}
public static void show( myclass you)
{
you.age = 24;
}
}
class myclass
{
public int age;
}
Don't confuse the variable and what the variable points to.
When you have:
MyClass myVar = new MyClass();
MyClass myVar2 = myVar;
That will create only a single instance of an object, but 2 variables pointing to it.
The same thing is happening to your parameter: you is a copy of the variable me, but both point to the same object. So when you modify you.age, you are also modifying me.age.
In your function, if you then did
you = new myClass();
only then would me and you refer to different objects. If you did this, me would still point to the original object.
If you added ref to the parameter you, then if you did
you = new myClass();
then the variable me would be updated to point to that same object.
For objects, you need to separate the variable from what the variable points to.
It's printing the right thing.
myclass is an object, and the default behavior is to pass the reference of the object in C#, so when you don't specify anything, you pass the reference.
If you declare struct myclass though, you'll have the behavior you want, because structs aren't references by default.
You're probably confusing this with C++ classes. In C#, classes are reference types, which means that whenever you have a variable of a type that's class, that variable doesn't hold the object itself, it holds only a reference to it (you can think of it as a pointer). So, when you pass your object into a method, you actually pass a reference to that object. This means the behavior you're observing is correct.
C# also supports value types (unlike e.g. Java), which you create by using struct instead of class. If you changed myclass into a srtuct, you would get the behavior you expected.
You are confusing value types and reference types.
public void addTwo(int a)
{
a += 2;
}
...
int a = 5;
addTwo(a);
Console.WriteLine(a); // will give "5";
public void addTwo(ref int a)
{
a += 2;
}
...
int a = 5;
addTwo(ref a);
Console.WriteLine(a); // will give "7";
For reference types (anything that is defined as class instead of struct, what you are passing on is a reference to the object, not a copy. So you are in fact changing the object.
You are sending an object to your function.
Not an atomic type or a struct, therefor it is sent by reference (this is how C# works), anything you change in this object in the function will also change in the original object because it is the same.
More information about passing parameters: http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx

C# reference member variable

In C#, is there a way to keep a reference as a member variable in an object (like an object pointer in C++), not just as a parameter?
EDIT: How can I make a pointer or reference to an object as a member variable?
No. Don't forget that the argument could reference a local variable which is out of scope by the time you use the object later on. A couple of options:
Use a mutable wrapper type
Use a delegate which captures the variable instead
Redesign your code to not require this in the first place
It's hard to know which is most suitable without knowing more about what you're trying to achieve, but ref is a dead-end.
If you mean ref the argument passing convention, then no, you cannot store this. From the first note on MSDN:
Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same...
Edit: based on your updated question, C# has different nomenclature about pointers and references. A pointer in C# is an unsafe construct used to somewhat directly reference the memory location of an object. I say somewhat because the memory location can change based on garbage collection (unless you fix it in memory).
References in C# are the default way reference types are passed and stored. They are akin to pointers in other languages, but not quite the same. However, the by-reference argument passing convention allows you to directly change what an object refers to.
If your objective is to keep a mutable reference to a non-reference type local variable, you'll have to encapsulate the local variable in a reference type (like a class). If you could give some sample code, we can give some specific examples.
Yes if it is a reference-type instance. And then it is the only way to store it in another class:
class Bar { }
class Foo
{
private Bar b; // b is a reference to a Bar
}
No if it's about a value-type, or a reference to a reference.
You would see simple object-references everywhere that C++ uses pointers, like in building Trees or Linked-Lists.
class Element { ...; private Element _next; }
For what its worth, you could use an array of size 1 as a reference/pointer. This yields more readable code than creating a new class to wrap a single value type member.
public struct StructWithReferenceMember
{
private int[] intStoredAsReference;
public StructWithReferenceMember(int asValue, int asReference)
: this()
{
IntStoredAsValue = asValue;
intStoredAsReference = new int[] { asReference };
}
public int IntStoredAsValue { get; set; }
public int IntStoredAsReference
{
get { return intStoredAsReference[0]; }
set { intStoredAsReference[0] = value; }
}
}
A similar trick can be used to attempt the highly discouraged practice of using mutable structs.
public class ReferenceProperty<T>
{
private T[] typeReference;
public ReferenceProperty(T value)
{
typeReference = new T[] { value };
}
public T PropertyAsValue
{
get { return typeReference[0]; }
set { typeReference[0] = value; }
}
public T[] PropertyAsReference
{
get { return typeReference; }
}
}
Then use array notation to "dereference" it.
public struct MutableStruct
{
public int member;
public MutableStruct(int value)
{
member = value;
}
}
ReferenceProperty<MutableStruct> referenceToValueType = new ReferenceProperty<MutableStruct>(new MutableStruct(3));
Console.WriteLine("original value: " + referenceToValueType.PropertyAsValue.member.ToString());
//referenceToValueType.PropertyAsValue.member = 4; // compiler error - cannot modify return value because it is not a variable
MutableStruct copyOfStruct = referenceToValueType.PropertyAsReference[0]; // or referenceToValueType.PropertyAsValue
copyOfStruct.member = 4;
Console.WriteLine("original value after modifying copy: " + referenceToValueType.PropertyAsValue.member.ToString());
referenceToValueType.PropertyAsReference[0].member = 5;
Console.WriteLine("original value after modifying reference: " + referenceToValueType.PropertyAsValue.member.ToString());
original value: 3
original value after modifying copy: 3
original value after modifying reference: 5
The way to get the address of a variable is the & operator, similar to C++. Again similarly to C++, you can store the address as a pointer:
class Foo
{
object* _objPtr;
Foo(object obj)
{
unsafe
{
_objPtr = &obj;
}
}
}
Note that any code that uses the address-of operator (&) or pointers must be within a method marked unsafe or within an unsafe code block.
This could be useful if you want to increase performance by not doing array bound-checking for example. The downside (besides safety considerations) is that the assembly must be fully-trusted for it to execute.
As pointed out, in C#, you very rarely actually store pointers, instead you store references so the garbage collector can operate properly. Ensure that you really need pointers in your code before using them!
For more info, see: http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx

Categories

Resources