繁体   English   中英

名单 <int> 在c#中

[英]List<int> in c#

我无法理解List<int>背后的逻辑,因为它打破了一些基本规则。

List<int>应该是值类型而不是引用类型。

  1. 如果必须在函数调用之间保持其值,则必须通过ref关键字传递List<int> 所以这意味着它正在显示类似于int的值类型行为。
  2. 但是List<int>必须由new运算符初始化。 List<int>也可以为null。 这意味着引用类型行为。

可空类型是不同的,因为它不必由新运算符初始化。

我在这看错了吗?

EDITED-

我应该在原始问题中发布代码。 但它遵循 -

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;
        }
    }
}

列表应该是值类型而不是引用类型。

错误! int是值类型。 List<int>是引用类型。

我认为你的第一颗子弹中有一个错误的假设。 通用List对象绝对是引用类型(在堆上,而不是堆栈)。 不确定为什么你认为你必须通过ref 这打印“2”就像它应该:

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);
      }
   }
}

您需要了解传递引用传递值按值传递引用之间的区别。

在您发布的代码示例中,要传递的参考 List<int>对象。 这意味着您可以改变引用指向的对象,并且调用代码将看到这些更改。 但是,引用本身是按值传递的,因此如果将引用更改为指向另一个对象,则调用代码将不会看到更改。

当您使用ref关键字时,您将通过引用传递引用。 这意味着您不仅可以更改引用指向的对象,还可以更改引用本身。

考虑这个例子:

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>确实是一个引用类型。 但列表中包含的项目是值类型。

然而,可以为Nullable的类型实现为结构( struct Nullable<T> where T : struct ),因此是值类型。 你可以简单写的原因

int? i = 3;

没有new关键字的是上述语法由编译器自动转换为将执行以下操作的代码:

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

为了更好地理解值类型和引用类型语义之间的差异,我建议您阅读Jon Skeet关于此主题的文章,该文章将为您提供大量示例代码示例:

Jon Skeet:C#中的参数传递

不要把它想象成List<int>以它写成List<t>的方式来思考它。

List是一个泛型类 它不是结构。 它是一个可以使用值类型和引用类型的泛型类。

List是一种通用引用类型,您使用值类型为int的类型。 但它仍然是一种参考类型。

在ModifyIt()方法中,当你写'l = returnList()'时; 'l'现在指向内存中的不同位置,而不是Test()方法中listIsARefType的位置。 基本上通过写'l''='某事,你打破了'l'和'listIsARefType'之间的联系。 为了保持链接(确保两个对象,'l'和'listIsARefType'指向内存中的相同位置),您需要只处理'l'对象(例如通过调用对象上的函数),或在ModifyIt()方法的参数中使用ref关键字。

List<int>是引用类型。 并且它不必作为参考传递。

类型列表的对象是值类型一种-的,不同的是值类型的对象可能最终装箱(转换成某种引用类型的对象),无论如何,一旦你明白so..scratch这一段。

除了在其他答案中处理的错误假设之外,你说:

List<int>必须由new运算符初始化...这意味着引用类型行为。

不,在C#中, new运算符只是调用类型构造函数的语法。 它用于引用和用户定义的值类型( struct )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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