How do I assign by "reference" to a class field in C#? - c#

I am trying to understand how to assign by "reference" to a class field in C#.
I have the following example to consider:
public class X
{
public X()
{
string example = "X";
new Y(ref example);
new Z(ref example);
System.Diagnostics.Debug.WriteLine(example);
}
}
public class Y
{
public Y( ref string example )
{
example += " (Updated By Y)";
}
}
public class Z
{
private string _Example;
public Z(ref string example)
{
this._Example = example;
this._Example += " (Updated By Z)";
}
}
var x = new X();
When running the above code the output is:
X (Updated By Y)
And not:
X (Updated By Y) (Updated By Z)
As I had hoped.
It seems that assigning a "ref parameter" to a field loses the reference.
Is there a way to keep hold of the reference when assigning to a field?

As others have noted, you cannot have a field of "ref to variable" type. However, just knowing that you cannot do it is probably unsatisfying; you probably also want to know first, why not, and second, how to get around this restriction.
The reason why is because there are only three possibilities:
1) Disallow fields of ref type
2) Allow unsafe fields of ref type
3) Do not use the temporary storage pool for local variables (aka "the stack")
Suppose we allowed fields of ref type. Then you could do
public ref int x;
void M()
{
int y = 123;
this.x = ref y;
}
and now y can be accessed after M completes. This means that either we're in case (2) -- accessing this.x will crash and die horribly because the storage for y no longer exists -- or we're in case (3), and the local y is stored on the garbage collected heap, not the temporary memory pool.
We like the optimization that local variables be stored on the temporary pool even if they are being passed by ref, and we hate the idea that you could leave a time bomb around that could make your program crash and die later. Therefore, option one it is: no ref fields.
Note that for local variables that are closed-over variables of anonymous functions we choose option (3); those local variables are not allocated out of the temporary pool.
Which then brings us to the second question: how do you get around it? If the reason you want a ref field is to make a getter and setter of another variable, that's perfectly legal:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
...
Ref<int> x;
void M()
{
int y = 123;
x = new Ref<int>(()=>y, z=>{y=z;});
x.Value = 456;
Console.WriteLine(y); // 456 -- setting x.Value changes y.
}
And there you go. y is stored on the gc heap, and x is an object that has the ability to get and set y.
Note that the CLR does support ref locals and ref returning methods, though C# does not. Perhaps a hypothetical future version of C# will support these features; I have prototyped it and it works well. However, this is not real high on the priority list, so I wouldn't get my hopes up.
UPDATE: The feature mentioned in the paragraph above was finally implemented for real in C# 7. However, you still cannot store a ref in a field.

No. ref is purely a calling convention. You can't use it to qualify a field. In Z, _Example gets set to the value of the string reference passed in. You then assign a new string reference to it using +=. You never assign to example, so the ref has no effect.
The only work-around for what you want is to have a shared mutable wrapper object (an array or a hypothetical StringWrapper) that contains the reference (a string here). Generally, if you need this, you can find a larger mutable object for the classes to share.
public class StringWrapper
{
public string s;
public StringWrapper(string s)
{
this.s = s;
}
public string ToString()
{
return s;
}
}
public class X
{
public X()
{
StringWrapper example = new StringWrapper("X");
new Z(example)
System.Diagnostics.Debug.WriteLine( example );
}
}
public class Z
{
private StringWrapper _Example;
public Z( StringWrapper example )
{
this._Example = example;
this._Example.s += " (Updated By Z)";
}
}

You forgot to update the reference in the Z class:
public class Z {
private string _Example;
public Z(ref string example) {
example = this._Example += " (Updated By Z)";
}
}
Output: X (Updated By Y) (Updated By Z)
Point to keep in mind is that the += operator for a string calls the String.Concat() method. Which creates a new string object, it doesn't update the value of a string. String objects are immutable, the string class doesn't have any methods or fields that lets you change the value. Very different from the default behavior of a regular reference type.
So if you use a string method or operator, you always have to assign the return value back to a variable. This is pretty natural syntax, value types behave the same way. Your code would be very similar if you used an int instead of a string.

Related

Variable Scope For an Extension Method

I have something interesting that I want to understand little deeper.
I have an extension class that extends int:
public static class MyExtension
{
public static void GetProp(this int i, MyObject o)
{
var val = i;
o.sum = i;
}
}
That uses a class as one of its parameter:
public class MyObject
{
public int sum { get; set; }
}
Now, lets see the unit test class:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void test()
{
int a = 1;
int b = 2;
int sum = 0;
Add(a, b, sum);
//Here, sum=3 but after its execution, sum looses its value and
retains the value sum = 0
int test = 4;
MyObject obj = new MyObject();
test.GetProp(obj);
But in the above code when I pass the variable using the extension
method, the obj.sum retains its value obj.sum = 4 . I am not passing any
value by reference. The first portion of code seems to follow the
passing ByVal. But the second portion of extension method, the value
is retained as if its passed as ByRef
string s = sum.ToString();
string p = obj.sum.ToString();
}
private void Add(int x, int y, int sum)
{
sum = x + y;
}
}
Can someone explain the mechanism behind this. Thanks
All parameters are send by value, unless you specify them with the ref or out keyword. Passing a parameter by value means that the value is copied.
However, when you pass an object by value it's not the object that is copied, it's the reference that is copied. That means that you have two references to the same object, one in the obj variable and one in the o parameter, but only one object.
When the extension method accessed the object, it's the same object as outside the method. Any change to the property made using the o parameter will be visible when you later access it using the obj variable.
This is the difference between passing by reference and passing a reference object (class). In GetProp, you aren't modifying the reference obj, you are modifying the MyObject instance that is referred by obj.
If I understand your question, you're confused about why the sum variable isn't changed when it is passed by value, but the obj.sum property does retain its value when obj is passed by reference. The other answers do a good job of explaining this.
In your question, you pass a parameter by value as a receiver, and this confuses your question a bit. Your question appears to be, "why is it that when I pass normally, it's treated as by-value, but when I pass as a receiver to an extension method, it's by-reference?"
Ah. Try assigning a new value to the receiver and see what happens at the call site:
public static void GetProp(this int i, MyObject o)
{
o.sum = i;
i = 5000;
}
You'll find that the variable test at the call site is not affected by this, since the receiver is also passed by value!

Struct initialization and new operator

I have two similar structs in C#, each one holds an integer, but the latter has get/set accessors implemented.
Why do I have to initialize the Y struct with new operator prior to assigning the a field? Is y still a value type when I init it with new?
public struct X
{
public int a;
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.a = 1;
Y y;
y.a = 2; // << compile error "unused local variable" here
Y y2 = new Y();
y2.a = 3;
}
}
The reason one is valid while the other is not is that you cannot call methods on uninitialised objects. Property setters are methods too.
public struct X
{
public int a;
public void setA(int value)
{ this.a = value; }
}
public struct Y
{
public int a { get; set; }
}
class Program
{
static void Main(string[] args)
{
X x;
x.setA(1); // A: error
x.a = 2; // B: okay
Y y;
y.a = 3; // C: equivalent to A
}
}
The reason that is not allowed is that the property setter could observe the uninitialised state of the object. The caller does not know whether the property setter merely sets a field, or does more than that.
In first case you just assigning field. It doesn't involve actual using of structure, just setting value into memory (struct address + field offset on stack).
In second case you calling method set_a(int value), but fail because variable is uninitialized.
In third case constructor initializes it for you, so using variable is ok.
Update: Here comes the specification!
"12.3 Definite assignment" (page 122 of ecma-334).
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned
This is covered in the C# specification section 5.3 dealing with "Definite Assignment":
a struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
and:
An initially unassigned variable (Section 5.3.2) is considered definitely assigned at a given location if all possible execution paths leading to that location contain at least one of the following:
* A simple assignment (Section 7.13.1) in which the variable is the left operand.
* ...
As such, this also works:
void Main()
{
X x;
x.a = 1;
x.b = 2;
x.Dump();
}
public struct X
{
public int a;
public int b;
}
You can test this in LINQPad.
Note that there is no way for the compiler to prove that the struct-type variable is considered definitely assigned if you call code on it, and that's what you're doing with a property. As such, before you can use a property on the struct-type variable, it has to be definitely assigned.
The new operator for value types runs the specified constructor. Unlike with reference types, this is optional, so if you don't use new, the default constructor is implicitly run (you cannot specify your own default constructor, so it always has the effect of giving the default value to the fields for their types).
As for why the compiler error, I'm not really sure. Interestingly, in the C# Interactive window,
public struct Y
{
public int a { get; set; }
}
Y test;
test.a = 5;
works just fine.

Why can struct change their own fields?

Consider the Foo struct as follows:
struct Foo
{
public float X;
public float Y;
public Foo(float x, float y)
{
this.X = x;
this.Y = y;
}
public void Change(float x)
{
this.X = x;
}
}
I understand modifying the field in the constructor, that's perfectly logical to me and my understanding of structs as value, number-like immutable types.
However, since one can't do:
Foo bar = new Foo(1, 2);
bar.X = 5;
Why can one use:
Foo bar = new Foo(1, 2);
bar.Change(5);
EDIT: If structs are mutable, then why can't they be modified when in a list or returned from a property?
Cannot modify expression because it is not a variable
Since one cannot do
Foo bar = new Foo(1, 2);
bar.X = 5;
Why can one use:
Foo bar = new Foo(1, 2);
bar.Change(5);
Your original question actually cannot be answered because it is predicated on a completely false assumption. Both code samples are perfectly legal, and so the question about why one is illegal is nonsensical. Let's move on to your follow-up question:
If structs are mutable, then why can't they be modified when in a list or returned from a property?
Because variables are mutable and values are immutable.
That's why they're called "variables", after all, because they can change.
When you say "bar.X = 5", "bar" is a local variable. Variables are allowed to change.
When you say "bar.Change(5)", "bar" is a local variable. Variables are allowed to change.
When you say "myArray[123].X = 5", "myArray[123]" is an array element and an array element is a variable. Variables are allowed to change.
When you say "myDictionary[123].X = 5", "myDictionary[123]" is not a variable. The value is returned from the dictionary, not a reference to the storage location. Since that is a value, not a variable, there is nothing there that can change, so the compiler does not allow it to change.
A subtle point is that when you attempt to change a field, the receiver must be a variable. If it is not a variable, it makes no sense; you are clearly attempting to mutate a variable and there's nothing there to mutate. When you call a method, the receiver must be a variable but what if you have a value? The method might not attempt to mutate anything, and so should be allowed to succeed. What the compiler actually does if the receiver of a method call on a struct is not a variable, then it makes a new temporary local variable and calls the method with that variable. So if you say: "myDictionary[123].Change(5);" that is the same as saying
var temp = myDictionary[123];
temp.Change(5);
Here "temp" is a variable, and the mutating method is allowed to change the temporary copy.
Is that now clear? The key takeaway here is variables can change.
You've made a key mistaken assumption.
.NET structs are mutable. You can absolutely perform bar.X = 5;.
You should design structs to be immutable, but by the code you have provided, they are mutable.
Have a look at this question for a description of where mutable structs can get your into trouble.
Immutability of structs
In common, all C# structs are not immutable, even readonly ones. So you can't design your structs as immutable at all.
All structs are mutable, just like in C++ :)
Immutability means that data structures ate immutable at language level, that is not true for C#.
I will show you how to break immutability rule using legal C# syntax, please note that NotReallyImmutableFoo.X is declared as a readonly field.
Cheers ;)
namespace test
{
public unsafe struct MutableFoo
{
public int Id;
public float X;
public MutableFoo(int id, float x) { Id = id; X = x; }
public void Change(float x)
{
unsafe
{
fixed (MutableFoo* self = &(this))
{
MutabilityHelper.Rewrite(self, x);
}
}
}
}
public struct NotReallyImmutableFoo
{
public long Id;
public readonly float X;
public NotReallyImmutableFoo(long id, float x) { Id = id; X = x; }
public void Change(float x)
{
unsafe
{
fixed (NotReallyImmutableFoo* self = &(this))
{
MutabilityHelper.Rewrite(self, x);
}
}
}
}
// this calls breaks up the immutability rule, because we are modifying structures itself
public static class MutabilityHelper
{
struct MutableFooPrototype
{
int Id;
float X;
public void Rewrite(float value)
{
X = value;
}
}
struct NotReallyImmutableFooPrototype
{
long Id;
float X;
public void Rewrite(float value)
{
X = value;
}
}
public static unsafe void Rewrite(NotReallyImmutableFoo* obj, float value)
{
NotReallyImmutableFooPrototype* p_obj = (NotReallyImmutableFooPrototype*)(*(&obj));
p_obj->Rewrite(value);
}
public static unsafe void Rewrite(MutableFoo* obj, float value)
{
MutableFooPrototype* p_obj = (MutableFooPrototype*)(*(&obj));
p_obj->Rewrite(value);
}
}
class Program
{
static void Main(string[] args)
{
MutableFoo foo = new MutableFoo(0, 2);
foo.X = 3; // X is writeable
foo.Change(5); // write X using pointer prototyping
NotReallyImmutableFoo nrifoo = new NotReallyImmutableFoo(0, 2);
// error CS0191
//nrifoo.X = 3; // X is not writeable
nrifoo.Change(3); // anyway, write X using pointer prototyping
}
}
}
Structures in .net combine piecewise mutability with shallow-copy-on-assignment semantics as well as the ability to pass by value-assignment or by reference. There is no convention in .net, however, by which classes would be expected to expose properties by reference, nor do any .net language compilers provide a convenient means of doing so. It would be possible for a language to provide such a feature, with certain limitations, by recognizing that something like:
somePoint.X = 5;
could be written as:
void SetXToFive(ref Point it) {it.X = 5;}
...
SetXToFive(ref somePoint);
allowing the code which manipulates the Point (by setting its X field to 5) from the code which has access to it. If an object which would have a property of type Point then exposes a routine which accepts a delegate to a method like the above, code that wants to set field X of that property to 5 could pass that routine a delegate to SetXToFive, which the routine could then call with whatever storage location holds the Point in question.
Note that one advantage over such an approach, compared with simply exposing a reference to the thing to be manipulated, is that the owner of the Point would know when the code that was manipulating it had finished. Without some compiler supper, the approach would generally be more of a nuisance than a benefit, but with compiler support the semantics could be made much cleaner than would be possible via any other means.

Storing a reference to an object in C#

I was wondering how one could store a reference to an object in .net.
That is, I would like something like the following code (note, of course, that the following code may be way off from how to actually do it):
class Test
{
private /*reference to*/ Object a;
public Test(ref int a)
{
this.a = a;
this.a = ((int)this.a) + 1;
}
public Object getA() { return this.a; }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(ref a);
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
To produce the following output:
4
4
Ideally, I would like to do this without writing a wrapper class around the integer.
In other words, I think I want pointers in .Net.
You cannot store references to variables in .NET, period. You can store references to objects, but not references to variables.
The reason is that if you were allowed to store references to arbitrary variables then you could store references to local variables. If you can store references to local variables then the runtime cannot use the optimization of storing local variables on the short-lived memory pool, aka, the stack.
Now, even if you could do that, the operation you are describing is not typesafe for a different reason. You have a (very badly named) field variable "a" of type "reference to object variable" and a (very badly and confusingly named) local variable "a" of type "reference to int variable". Even if you could store a reference to a variable it doesn't make any sense to store a reference to an int variable in something of type "reference to object variable" because those two types are logically not compatible. The operations you can perform on them are different; a reference to an object variable can have a string written into it; a reference to an int variable cannot.
Perhaps I am misunderstanding but wouldn't a variable such as the integer above be boxed into an object which could then be stored as a reference?
You are confusing references to objects with references to variables. It is confusing that we use the same terminology for what is really two different things.
Yes, boxing turns a value type, like int, into a reference type, like object. That has ABSOLUTELY NOTHING WHATSOEVER to do with references to variables.
When you make a ref to a variable you are making an alias for that variable. When you say
void M(ref int y) { y = 123; }
...
int x = 0;
M(ref x);
you are saying "x and y are two different names for the same variable".
Now, if what you want to do is represent the notion of "I have captured a variable and I want to be able to read and write it" then use delegates:
class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
int abc = 123;
var refabc = new Ref<int>(()=>abc, x=>{abc=x;});
... now you can pass around refabc, store it in a field, and so on
refabc.Value = 456;
Console.WriteLine(abc); // 456
Console.WriteLine(refabc.Value); // 456
Make sense?
C# has no concept of a reference variable akin to C++'s int& a. There are workarounds. One is to use closures:
class Test
{
private Func<int> get_a;
private Action<int> set_a;
public Test(Func<int> get_a, Action<int> set_a)
{
this.get_a = get_a;
this.set_a = set_a;
this.set_a(this.get_a() + 1);
}
public Object getA() { return this.get_a(); }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(() => a, n => { a = n; });
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
I'm not in front of VS, so please excuse any embarrassing faux pas.

Store a reference to a value type?

I am writing a "Monitor" object to facilitate debugging of my app. This Monitor object can be accessed at run time from an IronPython interpreter. My question is, is it possible in C# to store a reference to a value type? Say I have the following class:
class Test
{
public int a;
}
Can I somehow store a "pointer" to "a" in order to be able to check it's value anytime? Is it possible using safe and managed code?
Thanks.
You cannot store a reference to a variable in a field or array. The CLR requires that a reference to a variable be in (1) a formal parameter, (2) a local, or (3) the return type of a method. C# supports (1) but not the other two.
(ASIDE: It is possible for C# to support the other two; in fact I have written a prototype compiler that does implement those features. It's pretty neat. (See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.) Of course one has to write an algorithm that verifies that no ref local could possibly be referring to a local that was on a now-destroyed stack frame, which gets a bit tricky, but its doable. Perhaps we will support this in a hypothetical future version of the language. (UPDATE: It was added to C# 7!))
However, you can make a variable have arbitrarily long lifetime, by putting it in a field or array. If what you need is a "reference" in the sense of "I need to store an alias to an arbitrary variable", then, no. But if what you need is a reference in the sense of "I need a magic token that lets me read and write a particular variable", then just use a delegate, or a pair of delegates.
sealed class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
Ref<string> M()
{
string x = "hello";
Ref<string> rx = new Ref<string>(()=>x, v=>{x=v;});
rx.Value = "goodbye";
Console.WriteLine(x); // goodbye
return rx;
}
The outer local variable x will stay alive at least until rx is reclaimed.
No - you can't store a "pointer" to a value type directly in C#.
Typically, you'd hold a reference to the Test instance containing "a" - this gives you access to a (via testInstance.a).
Here is a pattern I came up with that I find myself using quite a bit. Usually in the case of passing properties as parameters for use on any object of the parent type, but it works just as well for a single instance. (doesn't work for local scope value types tho)
public interface IValuePointer<T>
{
T Value { get; set; }
}
public class ValuePointer<TParent, TType> : IValuePointer<TType>
{
private readonly TParent _instance;
private readonly Func<TParent, TType> _propertyExpression;
private readonly PropertyInfo _propInfo;
private readonly FieldInfo _fieldInfo;
public ValuePointer(TParent instance,
Expression<Func<TParent, TType>> propertyExpression)
{
_instance = instance;
_propertyExpression = propertyExpression.Compile();
_propInfo = ((MemberExpression)(propertyExpression).Body).Member as PropertyInfo;
_fieldInfo = ((MemberExpression)(propertyExpression).Body).Member as FieldInfo;
}
public TType Value
{
get { return _propertyExpression.Invoke(_instance); }
set
{
if (_fieldInfo != null)
{
_fieldInfo.SetValue(_instance, value);
return;
}
_propInfo.SetValue(_instance, value, null);
}
}
}
This can then be used like so
class Test
{
public int a;
}
void Main()
{
Test testInstance = new Test();
var pointer = new ValuePointer(testInstance,x=> x.a);
testInstance.a = 5;
int copyOfValue = pointer.Value;
pointer.Value = 6;
}
Notice the interface with a more limited set of template arguments, this allows you to pass the pointer to something that has no knowledge of the parent type.
You could even implement another interface with no template arguments that calls .ToString on any value type (don't forget the null check first)
You can create ref-return delegate. This is similar to Erik's solution, except instead of getter and setter it use single ref-returning delegate.
You can't use it with properties or local variables, but it returns true reference (not just copy).
public delegate ref T Ref<T>();
class Test
{
public int a;
}
static Ref<int> M()
{
Test t = new Test();
t.a = 10;
Ref<int> rx = () => ref t.a;
rx() = 5;
Console.WriteLine(t.a); // 5
return rx;
}
You can literally take a pointer to a value type using usafe code
public class Foo
{
public int a;
}
unsafe static class Program
{
static void Main(string[] args)
{
var f=new Foo() { a=1 };
// f.a = 1
fixed(int* ptr=&f.a)
{
*ptr=2;
}
// f.a = 2
}
}
class Test
{
private int a;
/// <summary>
/// points to my variable type interger,
/// where the identifier is named 'a'.
/// </summary>
public int A
{
get { return a; }
set { a = value; }
}
}
Why put yourself through all that hassle of writing complicated code, declaring identifiers everywhere linking to the same location? Make a property, add some XML code to help you outside the class, and use the properties in your coding.
I don't know about storing a pointer, don't think it's possible, but if you're just wanting to check its value, the safest way to my knowledge is to create a property of the variable. At least that way you can check its property at any time and if the variable is static, you wouldn't even have to create an instance of the class to access the variable.
Properties have a lot of advantages; type safety is one, XML tags another. Start using them!

Categories