2

I understand the rule. But who knows why this is?

If my code is:

List<T> x = new List<T>;
x.Add(new T());
x.Add(new T());
x.Add(new T());

int y = 2;

//And I call a method 
M1(ref x[y]);

ref x[y] is just a pointer to my instance of T of interest isn't it?

Why can't I write the line of code call it M1() in the very simple fashion.

.

I know the workaround:

T cX = x[y];
M1(ref cX);

I'm hoping to hear why the architects of c# require this extra step to pass a pointer? Or is it a compiler limitation?

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
Steve
  • 905
  • 1
  • 8
  • 32
  • 1
    `ref` and `out` apply to locations, not values. `x[y]` is a value of type `T` but `cX` is a location containing a `T`. – Lee Nov 04 '16 at 13:55
  • there are a [lot of questions](http://stackoverflow.com/questions/529782/c-sharp-property-and-ref-parameter-why-no-sugar) about this already. Look at the second answer on that link. – Jonesopolis Nov 04 '16 at 13:56

2 Answers2

3

An indexer value is not classified as a variable; therefore, you cannot pass an indexer value as a ref or out parameter.

Refer msdn

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
  • Thanks. I'll accept that the article notes an indexer is fairly more complex than I tend to think of it. But i will also get in future releases of c# compilers this construction constraint goes away. it is more complex and at the same time it is pretty simple. – Steve Nov 04 '16 at 14:00
1

ref x[y] is just a pointer to my instance of T of interest isn't it?

Well, if T is a reference type, then yes. If T is a value type then no, but that doesn't matter, let's assume for the moment it is. Since the method is ref T it needs to accept a reference to a variable which is pointer to an instance of T. You just have a pointer, not a storage location for a pointer. (Note that I'm staying within your analogy. Technically you don't have a "pointer", you have a reference to the object, but the analogy is good enough for the purposes of this question.)

The getter of the indexer of a list doesn't resolve to a storage location for a given value, it resolves to just a value. Also note that when you write:

T cX = x[y];
M1(ref cX);

That you're not reflecting any mutations of cX back to the list. You'd need to write:

T cX = x[y];
M1(ref cX);
x[y] = cX;

for it to actually be equivalent to ensure that any mutations to the variable cX in M1 are reflected in the list.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • then why when I modify a value of a property of cX is the modification persisted in x[y] after returning from M1()? – Steve Nov 04 '16 at 14:08
  • 1
    @Steve Because you're mutating the value that is referred to by the reference, you're not mutating the reference itself. If that's all that's happening the method shouldn't pass the parameter by reference in the first place, since it's not actually mutating the reference. (Note it should be *very* rare to pass parameters by reference; it's rarely the appropriate design for a method in general.) – Servy Nov 04 '16 at 14:10
  • Also a pointer is a memory address that contains a value that is a address to a memory location containing a value of interest. I see a reference to an object as a memory address containing the address of an instance of that object. To me seems much the same. How do you see it differently aside from the language? – Steve Nov 04 '16 at 14:11
  • got you on that ref parameters. – Steve Nov 04 '16 at 14:13
  • 2
    @Steve Technically references in C# is not the actual memory address of a value, but rather a number that the runtime associates with that value. It's not necessarily (it may be, but it doesn't *have* to be) the actual memory address. This is relevant in that C# is a garbage collected language, so the physical memory address of the value will be moving around constantly with each garbage collection, but the C# reference to that value is constant, and will refer to it even if/when the physical location moves. – Servy Nov 04 '16 at 14:18
  • 2
    The distinction is also relevant when dealing with *actual* pointers (which C# supports in `unsafe` code), often when ineroping with other languages, such as C/C++, that are dealing with actual physical memory addresses. When in such situations the difference between a C# reference and a physical memory address is very important. When not doing things like that the distinction is largely irrelevant. – Servy Nov 04 '16 at 14:19
  • Got ya. And thanks and makes good sense. Perhaps it would be best if I thought of a reference as a pointer to a pointer given garbage collection might move things around. And keep in mind the pointer to the pointer Isn't necessarily the value ofa memory address. – Steve Nov 07 '16 at 15:11