Skip to main content
GameDev.net gamedev.net
🔒 Locked

C# pass array elements by reference

Started by PunaProgrammer chris Jun 30, 2009 at 2:07 PM 7 replies 24.4k views
Original Post
PunaProgrammer chris
PunaProgrammer chris
I am trying to figure out how to pass an element of an array in C# by reference. As a simplified example I am looking to do something like this:

static void Main(string[] args)
{
    List<int> myList = new List<int>();
    myList.Add(1);
    Transformation(ref myList[0]);
}

static void Transformation(ref int number)
{
    number++;
}


However, this gives an error:
Quote:
A property or indexer may not be passed as an out or ref parameter.
I am fairly new to using C#, with most of my prior programming experience in C++, but for the most part it seems like C# is fairly loose with letting the coder do what they want, unless there is a safer or cleaner equivalent way of doing the same thing (with minimal change to the code required). So is there any way to do what I am trying to do, or I am just fighting with C# to get it to do something that it was designed not to do? P.S. Why doesn't ++ show up in the preview of my message?
dmatter
dmatter
Quote:
Original post by PunaProgrammer chris
So is there any way to do what I am trying to do, or I am just fighting with C# to get it to do something that it was designed not to do?
Imagine what could happen if C# allowed you to modify that variable in your transformation function, you would have a situation where you can get a value from an indexer/property getter and then change that value without going through the corresponding indexer/property setter (which could be private or involve some more complex logic than just a simple assignment). Clearly this cannot be allowed, although there are times when the compiler could conceivably figure out that it's safe to do but, for the time being at least, it doesn't.

What you need to do is assign the value from the getter to a temporary variable, pass that in to your function, then hand that back to the setter:

int temp = myList[0];Transformation(ref temp);myList[0] = temp;
Quote:
P.S. Why doesn't ++ show up in the preview of my message?
It's a known and illusive bug in the forum software.

MJP
MJP
Just to be clear here, you're talking about modifying an element of a List and not an array. It is perfectly valid to pass an element of an array (such as int[]) to a method by ref and then modify its value. However a List is not an array, it is a class that happens to internally use an array for storage and provides an indexed accessor property so that you can use the same syntax as an array for getting/setting values in the List.
PunaProgrammer chris
PunaProgrammer chris
Okay, I think I get it now. When I am trying to pass the element of the list by reference, I am not passing the actual element, but rather the thing returned by the getter for that element, so trying to do this doesn't make much sense. Right?

Also, after doing a bit more searching about C#, it appears that there is no way to pass objects as a read only reference (const & in C++). Doing this is useful for passing large chunks of data to a function with out having to make a copy of it, something that certainly comes up fairly often in game development, and often enough doing other kinds of programming too (like what I am working on now). Everything I read seemed to imply this didn't matter since it only affected performance, and programmers shouldn't care about performance... unless I'm horribly misunderstanding what these people are saying, what I should basically get out of this is that if performance matters, don't use C#?

Edit: Ah MJP, thanks. I don't know what I was thinking. But I think that it is possible to pass an element of a vector, which List seems to be the C# equivalent of, by reference in C++, no? At the very least by const reference.
Telastyn
Telastyn
Quote:
Original post by PunaProgrammer chris
Also, after doing a bit more searching about C#, it appears that there is no way to pass objects as a read only reference (const & in C++). Doing this is useful for passing large chunks of data to a function with out having to make a copy of it,


What makes you think that C# makes a copy of it?
PunaProgrammer chris
PunaProgrammer chris
Quote:
Original post by Telastyn
Quote:
Original post by PunaProgrammer chris
Also, after doing a bit more searching about C#, it appears that there is no way to pass objects as a read only reference (const & in C++). Doing this is useful for passing large chunks of data to a function with out having to make a copy of it,


What makes you think that C# makes a copy of it?


That was just the impression I got from reading the (possibly misinformed) posts elsewhere on the internet, for example this one.
So are you saying that C# won't actually perform this copying when passing by value? I would guess, if this is the case, that it just keeps track of the parts of the passed-by-value parameters that have been changed. If that is indeed what it does, that would be a pretty cool technique, however I'm somewhat skeptical that my guess is actually correct till somewhat informs me otherwise.
dmatter
dmatter
Quote:
Original post by PunaProgrammer chris
When I am trying to pass the element of the list by reference, I am not passing the actual element, but rather the thing returned by the getter for that element, so trying to do this doesn't make much sense. Right?
That's possible (imagine passing the Count property of the list to your function - would you seriously expect to be able to modify the count that way?). In this case however the indexer (which is really just a special kind of property, unlike C++ where it's an operator overload) is defined to simply return the same element that is stored in the list. The problem is that getters are just for getting values (mind blowing I know) and allowing you to pass a value returned from a getter by reference would effectively be allowing you to set a value using only a getter and not the setter.

Quote:
Also, after doing a bit more searching about C#, it appears that there is no way to pass objects as a read only reference (const & in C++).
That's right, although you can build immutable types and instances of those are then passed by reference (see below), the C# string is a good example of this.

Quote:
Doing this is useful for passing large chunks of data to a function with out having to make a copy of it
In C# classes, interfaces and delegates are all reference types, this means that instances of these are always passed by reference without any extra funky syntax needed. Enumerations, structs and numeric types are all value types, these get passed by value unless you use the out or ref modifiers.
Telastyn
Telastyn
Quote:
Original post by PunaProgrammer chris
Quote:
Original post by Telastyn
Quote:
Original post by PunaProgrammer chris
Also, after doing a bit more searching about C#, it appears that there is no way to pass objects as a read only reference (const & in C++). Doing this is useful for passing large chunks of data to a function with out having to make a copy of it,


What makes you think that C# makes a copy of it?


That was just the impression I got from reading the (possibly misinformed) posts elsewhere on the internet, for example this one.


That example is not mis-informed, but it is perhaps not applicable. There is a difference between 'not copying giant gobs of data' and 'sending a readonly reference'. The second is the idiomatic C++ way of achieving the first.

Quote:

So are you saying that C# won't actually perform this copying when passing by value?


C# will copy if you pass by value. Arrays aren't value types so you're not passing by value.
PunaProgrammer chris
PunaProgrammer chris
Quote:
Original post by dmatter
That's possible (imagine passing the Count property of the list to your function - would you seriously expect to be able to modify the count that way?). In this case however the indexer (which is really just a special kind of property, unlike C++ where it's an operator overload) is defined to simply return the same element that is stored in the list. The problem is that getters are just for getting values (mind blowing I know) and allowing you to pass a value returned from a getter by reference would effectively be allowing you to set a value using only a getter and not the setter.

Okay, thanks. This really helped to clear things up. I've never really learned C# besides from messing around with it and bits and pieces I've read online, so this whole concept of automatic getters and setters is still a bit foreign to me. I think I am starting to get the hang of it now.

Quote:
That's right, although you can build immutable types and instances of those are then passed by reference (see below), the C# string is a good example of this.

Alright, I will take a look into immutable types for future use.

Quote:
Original post by Telastyn
That example is not mis-informed, but it is perhaps not applicable. There is a difference between 'not copying giant gobs of data' and 'sending a readonly reference'. The second is the idiomatic C++ way of achieving the first.

True enough. I think I am just too used to using this approach since nearly every procedural language that I've used much allows some type of read only reference parameter passing.

Quote:
C# will copy if you pass by value. Arrays aren't value types so you're not passing by value.


Right. But just to be clear by I was trying to pass an element of an array (well, a list rather, but I believe for this part of the discussion the same rules apply), not the entire array itself, and the array was of value type elements, so it was passing by value. Anyway, I was clearly just Doing-It-Wrong here.
Thanks for all your help guys!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.