2012-11-29 44 views
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:

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

现在:

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

我的问题是,这将是确定的,如果我初始化订单对象在CustomerBO构造(或者)跳过它并在表示层中检查null。

+1

我很努力地在这里看到问题。你可以尝试更具体吗? –

+0

list2是浪费的(除非优化器将其移除),因为您在堆上分配了一个新项目,然后忽略它并将该变量分配给以前的内存地址。 –

+0

感谢您的回复。欣赏它。 – Sunny

回答

2

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

list3:它直接指向与list1相同的对象。

1

您不需要重新分配。当你声明一个变量时,内存被保留为包含数据的地址。当您执行像list2 = list1这样的分配时,您正在设置list2引用来引用与list1相同的内存地址。

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

2

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

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

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

另请注意,没有理由在线List<string> list2 = new List<string>();中有new List<string>()。您只需将list1分配给list2即可,因此您在使用之前丢弃新创建的列表。

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 
1
List<string> list1 = new List<string>() 
{ 
    "One", "Two","Three" 
}; 

打个比方:撕下一张纸把你的记事本,写上“此一张纸在顶部称为'list1'“。建一幢新房子,在房子里放上“一”,“两”和“三”,并在房间里写上房子的地址。

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

打个比方:撕裂纸张关闭记事本,写入“这张纸上被称为‘列表2’”在顶部。建造一所新房子,并在纸上写上房子的地址。

list2 = list1;  

类比:从名为“list2”的纸上擦除地址,并从名为“list1”的纸上复制地址。两份文件现在都保持相同的地址。

含义:建筑部门会偶尔检查每个人的文件。他们到每张纸上的每个地址,并在他们在那里找到的房屋上画一个绿色的复选标记。然后他们拆除没有绿色复选标记的所有房屋。你刚刚创建的房子(你在“list2”文件中被覆盖的地址)将在不久的将来被销毁;没有人会涉足这座房子,你的建筑努力被浪费了。

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

打个比方:转到地址“列表2”的纸张,从屋内获得每个项目,并在报上发表它

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”论文,获得各从房子里面出来,然后在报纸上打印。当然,在这一点上,所有的文件都有相同的地址,所以你要去同一所房子;你将因此两次列出同一家的内容。

+0

感谢您花时间提供类比。欣赏它。 – Sunny

+0

@Sundeep不客气。类比的基本思想来自Eric Lippert。如果你还不知道他的博客,你可能想看看它,或浏览他对这个网站的贡献:http://blogs.msdn.com/b/ericlippert和http:// ericlippert。 com /和http://stackoverflow.com/users/88656/eric-lippert – phoog

相关问题