[.net] Reference to a value type in C#

Started by
9 comments, last by leidegren 16 years, 7 months ago
Is it possible in C# to get a reference to an object of a value type? Consider the code:

struct S
{...}

S s1[] = new S[10];
S s2[] = new S[10];

...

int i = ... //0 <= i < 20

S s = (i < 10) ? s1 : s2;
<span class="cpp-comment">//Do something with s</span>


</pre></div><!–ENDSCRIPT–>

Suppose "do something with s" involves modifying s. Since s is a copy of the array element, any modifications will be made to the copy. What can I do if I want to actually alter the array element itself? In C++, this would be a simple matter of making s a reference ("S & s"); is there a similar construct in C#?
Advertisement
Nope. You could do all kinds of hacks with pinning and taking the address of the array element, but if you really want to do that you should be using a reference type.

In your case you could just get away with storing the new index and then operating directly on that element, or modifying s and then copying it back into the array.
Ra
You could pass it as a reference to a function:

void SomeFunction(){    Point [] points = new Point[10];    DoSomething(ref points[4]);}void DoSomething(ref Point p){    p.X = 4;}


This works for arrays and variables but does not work with properties or indexers in generic containers, like List<Point>.
Quote:Original post by Ra
In your case you could just get away with storing the new index and then operating directly on that element, or modifying s and then copying it back into the array.


Thanks. It looks like modifying and then copying back is the best solution in this situation.

Quote:Original post by kanato
You could pass it as a reference to a function:

DoSomething(ref points[4]);



Unfortunately this won't work here:
ref ((i < 10) ? s1 : s2)</pre>causes an error about "ref" requiring an assignable object.
Quote:Original post by bakery2k1
Unfortunately this won't work here:
ref ((i < 10) ? s1 : s2)</pre>causes an error about "ref" requiring an assignable object.<!–QUOTE–></td></tr></table></BLOCKQUOTE><!–/QUOTE–><!–ENDQUOTE–><br><br>if (i &lt; 10) DoSomething(ref s1<span style="font-weight:bold;">);<br>else DoSomething(ref s2[i-10])<br><br>:)<br><br>
It's very possible! And very easy, but it usually involes unsafe code, which is perfectly fine but should be used with care as it's not really CLR best practice.

inside a unsafe { } code block you are allowed to use the address of operator & to get a pointer of any value type. You can do this for any .NET type (classes as well) but it can quickly get error prone.

As long as your struct S is a non-managed type you can do this.

S s = new S(); // initialize
S* p = &s

This is very similar to the ref keyword for passing something as a reference, but it's more powerful. Since it's not a managed pointer.

If you have an array you can use a fixed statment inside a unsafe code block to lock memory down to really do something cool.

fixed( S* p1 = s1 )
{
fixed( S* p2 = s2 )
{
S* s = i < 10 ? p1 + i : p2 + i - 10;
// do something with 's'
}
}

It's like pointers in C, and it's generally bad CLR practice but it will do the trick, and if you need this, this is what you need to do.

Side note: Since C# is managed, memory is collected automatically, but it's also moved around. The fixed statment prevents the CLR from moving memory, and it's a bad thing if you do GC collect with fixed memory. A simple way to avoid it is to just fix memory wherever needed, and only for the duration of the procedure. It's could impose a preformance problem, but as with all things, profile it!

There is a struct called GCHandle which can be used for really advanced stuff and with managed reference types, look it up on MSDN if you want to use it.
I am trying to figure out why you are trying to get a value type act like a reference type?

If your type is mutable, you should probably use a class.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Replace the word "struct" with "class". FIXED!
Quote:Original post by Niksan2
if (i < 10) DoSomething(ref s1);
else DoSomething(ref s2[i-10])

:)


Of course! [rolleyes]

Quote:Original post by paulecoyote
I am trying to figure out why you are trying to get a value type act like a reference type?

If your type is mutable, you should probably use a class.


When to use a struct and when to use a class is something I'm still trying to figure out. Thinking about it, "mutable => class" seems to be a good guideline.

Is there any similar advice that would make my life easier?
Most of the time you will want to use reference types. Value types should be used for what their name implies: objects that act as a value, such as integers, Matrices, vectors, floats, points, coordinates, etc.
Mike Popoloski | Journal | SlimDX

This topic is closed to new replies.

Advertisement