0

I was reading the MSDN page about the ref keyword and modified the example using a collection instead of an int, like so:

public static void Main(string[] args)
{
    List<int> elements = new List<int>();
    Method(elements);               

    foreach(int val in elements)
    {
        Console.WriteLine(val);
    }
 }

static void Method(List<int> addelements)
{
        addelements.Add(1);
        addelements.Add(20);    
}

Why is it that without the ref keyword I can see the ints added to the collection outside of the method? When it was just int val I needed the ref to see what changes the method made, but with a List<int> not so, why is this?

Update:

One more question, I now understand the ref keyword and Lists. With that in mind, is doing the following redundant:

public static void Main(string[] args)
{
    List<int> elements = new List<int>();
    elements = Method(elements);                

    foreach(int val in elements)
    {
        Console.WriteLine(val);
    }
 }

static List<int> Method(List<int> addelements)
{
        addelements.Add(1);
        addelements.Add(20);
        return addelements;     
}
Rook
  • 5,734
  • 3
  • 34
  • 43
  • 3
    This is a very common confusion; the fact that you can have a "ref" to a variable that contains *a reference* is confusing. Try reading Jon's article on the subject and see if it sorts you out. http://jonskeet.uk/csharp/parameters.html – Eric Lippert Mar 01 '16 at 13:05
  • `List` is a reference type, `int` is a value type. – Tim Schmelter Mar 01 '16 at 13:05
  • 1
    Your code is not creating a new list object, it merely modifies it. So no *ref* required. Consult your favorite C# introduction book about the difference between reference types and value types, it is very important. – Hans Passant Mar 01 '16 at 13:05
  • 1
    The key understanding to come away with is that "with the ref I can see what changes the method made" is the wrong way to think of it. The right way to think of it is "ref allows me to make one variable into an alias for another". – Eric Lippert Mar 01 '16 at 13:07
  • @TimSchmelter - So the list is passing a reference of it's data without the use of the ref keyword, correct? –  Mar 01 '16 at 13:09
  • 1
    @Svetlana: not quite, the list's reference is passed so you can work with the original but you can't replace the passed list inside the method. If you pass a value type it's copied, so you have no access to the original object. But i suggest to read what E. Lippert has posted in his first comment. [This](https://msdn.microsoft.com/en-us/library/9t0za5es.aspx) can also help to understand it. – Tim Schmelter Mar 01 '16 at 13:10
  • this may help :http://www.codeproject.com/Articles/1037209/Story-of-Pass-By-Value-and-Pass-By-Reference-in-Cs – Ehsan Sajjad Mar 01 '16 at 13:25
  • Possible duplicate : http://stackoverflow.com/questions/7321602/why-is-list-when-passed-without-ref-to-a-function-acting-like-passed-with-ref – Pradip Mar 01 '16 at 13:32
  • Read more [Value and Reference Types](https://msdn.microsoft.com/en-us/library/4d43ts61%28v=vs.90%29.aspx), [Types (C# Reference)](https://msdn.microsoft.com/en-us/library/3ewxz6et.aspx). These will help you a lot. – shadow Mar 01 '16 at 14:06

2 Answers2

0

In c# there two kind of objects Reference type and value type. (Pointer Type in case of unsafe) when passing in function :

1) Refs are passed by reference // no need for ref

2) Values are passed by copy // you can use ref here to prevent that behaviour

static void Method(List<int> addelements)  // list is referance type

List is referance type, it is a container for integers, so if container is mutable you can mutate it ...

Second question: Depends on what you are doing in that method...

1) If you want to reuse that method later it will be good idea

2) if you have huge amount of lines of code on that List, you can make it more descriptive do separate them as methods with descriptive names and call them in order rather than doing it in one method body... (sort of release eye and brain strain :) )

Davit Tvildiani
  • 1,915
  • 3
  • 19
  • 29
  • That's not quite true. There are three. [Types (C# Reference)](https://msdn.microsoft.com/en-us/library/3ewxz6et.aspx) We just use two in most cases. – shadow Mar 01 '16 at 13:56
  • @Davit Tvildiani - I updated my question, have a look, and answer –  Mar 01 '16 at 14:41
0

In C# there are two kinds of types: reference and value types (there is also a pointer type, but is only used in unsafe contexts)

Value types contain the value directly, while reference types contain a reference to the data.

Value Types

When passing a variable of value type as a parameter, the method receives a copy of the original object, so that any modification made inside the method will not persist.

Value types consist of all numerical types, bool and enumerations and structs you define yourself.

(The main types that are value are structs and enumerations, since the numerical values and the bool are implemented as struct).

Note that you can still pass a value type by reference by using the ref keyword.

Reference types

When passing a reference type as a parameter, the method receives a copy of the reference, so the method will work with the same object. So any modification made inside the method will persist.

In C#, string has a special behavior. It is passed by reference and is immutable (it cannot be modified - if you modify a string object, the new value is copied into another object and your old variable references your new value.)

Every user-defined class, interface and delegate is passed by reference. Also, every array is passed by reference.

So, in your case, you pass a List<int> which is an instance of a class, so it is passed by reference.

Hope this clarifies things a bit.

Best of luck!

Update based on the new question

Just as @fafase said, you are doing two things there:

  • when you add elements to the list (in the method), you are modifying the original list.
  • when you return the same reference, so when you do:

elements = Method(elements); you actually assign elements to the list you return from the method (which is the same you passed in the first place, since it is passed by reference)

In short, if you only need to modify the list, simply do it in a void method, like in the original question.

radu-matei
  • 3,469
  • 1
  • 29
  • 47
  • I have one more question, let me update my code, can you please have a look? –  Mar 01 '16 at 14:36
  • I updated my question, please have a look and answer. –  Mar 01 '16 at 14:40
  • 1
    You second part is not necessarily redundant, it does two different actions leading to the same result. You update the list and then assign that same list to the original reference. – Everts Mar 01 '16 at 14:49
  • 1
    "*When passing a reference type as a parameter, the method receives the actual reference to the object*" I would word that slightly different, maybe "the method receives a copy **of the reference** to the object". To show that a copy is still happening but the copy is of the reference not of the value the reference points to like in value types. – Scott Chamberlain Mar 01 '16 at 15:06
  • @ScottChamberlain Thanks for the feedback! – radu-matei Mar 01 '16 at 15:15