简体   繁体   中英

List<int> in c#

I am unable to understand the logic behind List<int> as it breaks some of the basic rules.

List<int> is supposed to be of value type and not reference type.

  1. List<int> has to be passed by ref keyword if its value has to be persisted between function calls. So this means it is displaying a value type behavior similar to int.
  2. But List<int> has to be initialized by a new operator. Also List<int> could be null as well. This implies a reference type behavior.

A nullable type is different as in it does not have to be initialized by new operator.

Am I seeing something wrong here?

EDITED-

I should have posted the code in the original question itself. But it follows here -

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ListTest d = new ListTest();
            d.Test();
        }
    }

    class ListTest
    {
        public void  ModifyIt(List<int> l)
        {
            l = returnList();
        }

        public void Test()
        {
            List<int> listIsARefType = new List<int>();
            ModifyIt(listIsARefType);
            Console.WriteLine(listIsARefType.Count); // should have been 1 but is 0
            Console.ReadKey(true);
        }

        public List<int> returnList()
        {
            List<int> t = new List<int>();
            t.Add(1);
            return t;
        }
    }
}

List is supposed to be of value type and not reference type.

Wrong! int is a value type. List<int> is a reference type.

I think you have a faulty assumption in your first bullet. The generic List object is definitely a reference type (on the heap, not the stack). Not sure why you think you have to pass via ref . This prints "2" like it should:

namespace ConsoleApplication1 {
   class Program {
      static void Main(string[] args) {
         List<int> listIsARefType = new List<int>();
         ModifyIt(listIsARefType);
         ModifyIt(listIsARefType);
         Console.WriteLine(listIsARefType.Count); // 2!
         Console.ReadKey(true);
      }

      static void ModifyIt(List<int> l) {
         l.Add(0);
      }
   }
}

You need to understand the difference between pass by reference , pass by value , and pass reference by value .

In the code sample you posted, you're passing the reference to the List<int> object by value . This means that you can mutate the object pointed to by the reference, and the calling code will see these changes. However, the reference itself is passed by value, so if you change the reference to point to a different object altogether, the calling code will not see the changes.

When you use the ref keyword, you're passing the reference itself by reference. This means that not only can you change the object that the reference is pointing to, but you can also change the reference itself.

Consider this example:

class Program
{
    static void Main()
    {
        int foo = 0;
        DoSomething1(foo);
        Console.WriteLine(foo); // Outputs 0.

        DoSomething1(ref foo);
        Console.WriteLine(foo); // Outputs 1.

        var bar = new List<int>();
        DoSomething2(bar);
        Console.WriteLine(bar.Count); // Outputs 1.

        DoSomething2(ref bar);
        Console.WriteLine(bar.Count); // Outputs 0.
    }

    // Pass by value.
    static void DoSomething1(int number)
    {
        // Can't modify the number!
        number++;
    }

    // Pass by value.
    static void DoSomething1(ref int number)
    {
        // Can modify the number!
        number++;
    }

    // Pass reference by value.
    static void DoSomething2(List<int> list)
    {
        // Can't change the reference, but can mutate the object.
        list.Add(25);
    }

    // Pass reference by reference.
    static void DoSomething2(ref List<int> list)
    {
        // Can change the reference (and mutate the object).
        list = new List<int>();
    }
}

List<int> is indeed a reference type. But the items contained in the list are value types.

Nullable types however are implemented as structs ( struct Nullable<T> where T : struct ) and are therefore value types. The reason that you can simply write

int? i = 3;

without the new keyword is that the above syntax is translated by the compiler automatically into code that will do the following:

Nullable<Int32> i = new Nullable<Int32>(3);

To get a better understanding of the differences between value type and reference type semantics I would recommend you to read Jon Skeet's article on this topic which will guide you with lots of illustrative code sample:

Jon Skeet: Parameter passing in C#

Don't think of it as List<int> think of it the way that it was written List<t> .

List is a generic class . It is not a struct. It is a generic class that can work with value types and reference types.

A List is a generic reference type, you are using it with a value type int. But it is still a reference type.

In ModifyIt() method, when you are writing 'l = returnList()'; 'l' is now pointing to a different location in the memory than that of listIsARefType in your Test() method. Basically by writing 'l' '=' something, you have broken the link between 'l' and 'listIsARefType'. In order to keep the link (that is making sure that both of the objects, 'l' and 'listIsARefType' are pointing to the same location in the memory), you either need to only work on the 'l' object (for example by calling a function on the object), or use the ref keyword in the parameter of the ModifyIt() method.

List<int> is a reference type. And it doesn't have to be passed as a reference.

The type of the objects in the list is kind-of a value type, except that value-type objects may end up boxed (converted into reference-type objects of a sort) anyway, so..scratch this paragraph once you understand that.

In addition to the mistaken assumptions dealt with in other answers, you say:

List<int> has to be initialized by a new operator... This implies a reference type behavior.

No, in C# the new operator is just the syntax for calling the constructor of a type. It's used for both reference and user-defined value types ( struct s).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM