2010-10-27 123 views
52

给出下面的代码,position0的初始化方式和position1的初始化方式有什么区别?它们是否相同?如果不是,有什么区别?C#新语句后的大括号是什么?

class Program 
{ 
    static void Main(string[] args) 
    { 
     Position position0 = new Position() { x=3, y=4 }; 

     Position position1 = new Position(); 
     position1.x = 3; 
     position1.y = 4; 
    } 
} 

struct Position 
{ 
    public int x, y; 
} 

回答

41

对象和集合初始化器,用于初始化对象上的字段。

http://msdn.microsoft.com/en-us/library/bb384062.aspx

他们生产几乎相当于 IL。 Jon Skeet对真正发生的事情有了答案。

+1

很多事实。张贴我的答案...看到他的答案,编辑它指出他的答案。 – 2010-10-27 16:45:32

+0

乔恩Skeet似乎回答在这个网站上的每个问题:)我迫不及待地阅读他的新书(如果它实际上得到释放) – Bryan 2010-10-27 16:55:01

1

这些完全等同。编译器实际上只是将第一个版本转换为第二个版本。

两者之间的唯一区别是,第一,你可以做很好的变薄,如通过初始化版本的方法:

DoSomethingWithPoint(new Position() { x=3, y=4 }); 

这是一个代码很多线路比第二初始化例。

2

您的两个代码示例将生成相同的IL。 (至少在发布版本中)

5

这是一个对象初始化程序,只是允许您在单个表达式中分配值。最重要的是,这也适用于LINQ an中的匿名类型(否则不可变)。 addi项目也有类似的集合初始化语法到新的集合。

请注意,有一个微妙的时间问题是有用的;与初始化的分配/添加全部发生之前该变量被分配,这可以帮助阻止其他线程看到一个不完整的对象。否则,您需要额外的变量才能达到相同的结果。

+0

约书亚和斯拉克斯公布,初始化'位置'的两种方式产生等效的IL。你是说用匿名类型,我会得到不同的结果? – 2010-10-27 15:12:46

+0

@rice - 是的:只有其中一个会编译:) – 2010-10-27 15:14:27

1

它们是等价的,除了一个比另一个更容易阅读。

还要考虑的情况下,当你想通过新的对象一起到别的地方:

var aList = new List<Position>(); 
aList.Add(new Position() { x=3, y=4 }); 
51

他们不是相当等同 - 至少不是在一般情况下。使用对象初始化的代码更接近这样的:

Position tmp = new Position(); 
tmp.x = 3; 
tmp.y = 4; 
Position position1 = tmp; 

换句话说,分配给变量只发生后的属性已被设置。现在,如果你声明了一个新的局部变量,那实际上并不重要,编译器可能会优化你的第一个表单。但从逻辑上讲,这很重要。试想一下:

Position p1 = new Position { x = 10, y = 20 }; 

p1 = new Position { x = p1.y, y = p1.x }; 

如果没有分配给p1第一,你最终以0两个p1.xp1.y。而这实际上相当于:

Position tmp = new Position(); 
tmp.x = 10; 
tmp.y = 20; 
Position p1 = tmp; 

tmp = new Position(); 
tmp.x = p1.y; // 20 
tmp.y = p1.x; // 10 
p1 = tmp; 

编辑:我刚刚意识到你正在使用一个结构,而不是一个类。这可能会产生一些细微的差异......但你几乎肯定不应该使用可变结构来开始:)

2

忘记所有IL的东西,它只是简写符号。你在做什么是这样的:

a。在一种情况下,您明确使用默认的构造函数,然后设置两个属性。

b。另一方面,您正在使用新的初始化语法,它隐式地使编译器执行您在大小写a中执行的操作。

IL subtelties尽管他们会为你实现同样的事情。