这可能是一个基本问题,但任何人都可以解释这是如何工作的。下面的代码只是示例,但实时这种情况可能发生在各个地方。例如:为具有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是否可以。
答案 0 :(得分:2)
list2:你首先创建一个空列表,然后你摆脱它并使list2指向与list1相同的对象。
list3:它直接指向与list1相同的对象。
答案 1 :(得分:2)
行:List<string> list3 = list1;
没有复制列表,它只是将引用复制到列表中,因为List
与C#中的所有类一样,是一个引用类型。 list3
不是新列表,它只是访问上面列出的相同列表的另一种方式。这可能没问题,也可能没有,很难说出你期望的是什么,以及在一个不那么人为的例子中你可能需要哪些。
if (list3 != null) //is this the only difference
至于你是否需要那条线,这取决于。如果在创建列表和使用它之间执行某些代码可能导致list3
为空,那么检查它可能是一个好主意。没有更“真实”的例子,很难说出来。在给定的示例中,由于list3
不能为空,因此不需要它。
另请注意,没有理由在new List<string>()
行中添加List<string> list2 = new List<string>();
。您只需立即将list1
分配给list2
,这样您就可以在使用之前丢弃新创建的列表。
答案 2 :(得分:1)
您无需重新分配。声明变量时,会保留内存以包含数据的地址。当您执行list2 = list1
之类的作业时,您要设置list2
引用以引用与list1
相同的内存地址。
如果您首先初始化list2
,那么您只是创建一个对象,该对象将被垃圾收集器回收而不被使用。
答案 3 :(得分: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
答案 4 :(得分: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”纸张上的地址,从房子内取出每件物品,然后将其打印在报纸上。当然,此时所有的论文都有相同的地址,所以你要去同一个房子;因此,您将两次列出同一所房子的内容。