0

这可能是基本问题,但任何人都可以解释这是如何工作的。下面的代码只是示例,但实时这种情况可能会发生在不同的地方。例如:在为具有 Orders 属性的复杂对象(如 Customer)创建 DTO 时。Orders (=List) 是否需要在 Customer 的构造函数中实例化,还是直接将其分配给查询结果或存储过程。

List<string> list1 = new List<string>()
{
    "One", "Two","Three"
};

List<string> list2 = new List<string>();
list2 = list1;        
foreach (var s in list2)
  Console.WriteLine(s);

List<string> list3 = list1;
if (list3 != null) //is this the only difference
{
 foreach (var s in list3)     
     Console.WriteLine(s);     
}

我尝试检查 IL 代码,但它不是自我解释的。

    IL_0031: stloc.0
    IL_0032: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
    IL_0037: stloc.1
    IL_0038: ldloc.0
    IL_0039: stloc.1
    IL_003a: ldloc.0
    IL_003b: stloc.2
    IL_003c: nop
    IL_003d: ldloc.1
    IL_003e: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
    IL_0043: stloc.s CS$5$0000

我很抱歉发布了一个令人困惑的例子。下面是实际场景

DTO:

public class CustomerBO
{
        public CustomerBO()
        {
            Orders = new List<OrderBO>(); 
        }
       List<OrderBO>() Orders { get; set;}
      //other properties of customer
}

现在在 DAL 层:

objCustomer.Orders = Repository.GetAll<OrderBO>("dbo.GetOrdersList");

我的问题是,如果我在 CustomerBO 构造函数中初始化 Orders 对象(或)跳过它并在表示层中检查 null 是否可以。

4

5 回答 5

2

list2:您首先创建一个空列表,然后将其删除并使 list2 指向与 list1 相同的对象。

list3:与list1直接指向同一个对象。

于 2012-11-29T21:32:22.637 回答
2

行:List<string> list3 = list1;不是复制列表,它只是复制对列表的引用,因为 与ListC# 中的所有类一样,是一个引用类型。 list3不是一个新列表,它只是访问上面相同列表的另一种方式。这可能很好,也可能不是,在一个不太人为的例子中,很难说出你期待什么以及你可能需要什么。

if (list3 != null) //is this the only difference

至于你是否需要那条线,这取决于。如果在创建列表和使用它之间执行了一些可能导致list3为空的代码,那么检查它可能是一个好主意。没有更“真实”的例子很难说。在给出的示例中,不需要它,因为它list3永远不能为空。

另请注意,没有理由new List<string>()排队List<string> list2 = new List<string>();。您只是立即分配list1list2,因此您在使用之前丢弃了新创建的列表。

于 2012-11-29T21:34:13.960 回答
1

您无需重新分配。声明变量时,会保留内存以包含数据的地址。当您执行类似 的分配时list2 = list1,您将引用设置为list2引用与 相同的内存地址list1

如果您list2先初始化,您只是创建了一个对象,该对象将被垃圾收集器回收而不被使用。

于 2012-11-29T21:33:46.383 回答
1

我相信下面的示例可以阐明分配列表对象和创建新列表对象之间的区别:

var l1 = new List<string>()
{
    "One", "Two","Three"
};

var l2 = l1;
l1.SequenceEqual(l2);           // true
Object.ReferenceEquals(l1, l2); // true

var l3 = new List<string>();
foreach (var s in l1)
    l3.Add(s);
l1.SequenceEqual(l3);           // true
Object.ReferenceEquals(l1, l3); // false
于 2012-11-29T21:43:46.703 回答
1
List<string> list1 = new List<string>()
{
    "One", "Two","Three"
};

类比:从记事本上撕下一张纸,在最上面写下“这张纸叫做‘list1’”。盖新房子,把“一”、“二”、“三”放在房子里,把房子的地址写在纸上。

List<string> list2 = new List<string>();

类比:从记事本上撕下一张纸,在最上面写下“这张纸叫做‘list2’”。盖一所新房子,把房子的地址写在纸上。

list2 = list1;      

类比:从名为“list2”的文件中删除地址,并从名为“list1”的文件中复制地址。两份文件现在拥有相同的地址。

含义:建筑部门偶尔会检查每个人的文件。他们去每张纸上的每个地址,并在他们在那里找到的房子上画一个绿色的复选标记。然后他们拆除了所有没有绿色复选标记的房屋。您刚刚创建的房子(您在“list2”纸上覆盖的地址)将在不久的将来被摧毁;没有人会踏入那所房子,而你建造它的努力付诸东流。

foreach (var s in list2)
  Console.WriteLine(s);

类比:去“list2”纸上的地址,从房子里取出每件物品,然后打印在报纸上(抱歉,类比不成立!)

List<string> list3 = list1;

类比:从记事本上撕下一张纸,在最上面写下“这张纸叫做‘list3’”。将“list1”中的地址复制到这张新的“list3”纸上。

if (list3 != null) //is this the only difference
{

类比:检查“list3”纸上是否写有地址。(顺便说一句,这在这段代码中不是必需的,因为我们可以证明它必须有一个写在上面的地址。)

 foreach (var s in list3)     
     Console.WriteLine(s);     
}

类比:到“list3”纸上的地址,从房子里取出每件物品,然后打印在报纸上。当然,此时所有的文件上都有相同的地址,所以你要去同一个房子;因此,您将两次列出同一所房子的内容。

于 2012-11-29T21:51:45.010 回答