C#3.0新特性(二)- 初始值设定项

一、自动属性:

  在C# 2.0中,我们对成员进行封装,也就是自动属性,如下示例:

private int m_one;
public int One
{
  get { return m_one; }
  set { m_one = value; }
}

这种方式只需写第一句代码,然后用Visual Studio的Refactor->Encapsulate Field功能,很方便,也早已经为大家熟知。而在C# 3.0中,我们只需要写成如下一句就可以了:

public int Dne { get; set; }// Auto-implemented properties

可以看出,C# 3.0中这种自动属性对C# 2.0中的属性写法作了大大的简化。C# 3.0的自动属性就不需要创建私有变量,而把这个工作交给编译器代劳!当然,如果需要在获取访问器get或设置访问器set里头添加一些逻辑,扩展也很方便。


  二、对象初始值设定项
  使用对象初始值设定项可以在创建对象时向对象的任何可访问的字段或属性分配值,而无需显式调用构造函数。对象初始值设定项,我在很多地方看到,其名称,又叫对象初始化器。看实例,以前,我们首先定义一个类:

public class MyClass
{
  public string Number { get; set; }
  public string Name { get; set; }
  public MyClass()
  {
  }
  public MyClass(string newID)
  {
    Number = newID;
  }
  public MyClass(string newID, string newName)
  {
    Number = newID;
    Name = newName;
  }
}

然后,new一个对象,并对其属性初始化:

public static void newObject()
{
  MyClass cobject = new MyClass();
  cobject.Name = "yy";
  cobject.Number = "1111";
  MyClass dobject = new MyClass("1111");
  dobject.Name = "yy";
  MyClass eobject = new MyClass("1111","yy");
}

现在,在C# 3.0中,利用对象初始化器,new一个对象,并对可以访问的属性初始化,只需要如下一句代码:

MyClass nobject = new MyClass{Name = "yy",Number = "1111"};

该属性的类的定义如下:

public class OClass
{
  public string addr { get; set; }
  public string zip { get; set; }
  public OClass()
  {
  }
  public OClass(string address, string zipCode)
  {
    this.addr = address;
    this.zip = zipCode;
  }
}

然后,在newObject方法中,new一个新对象完全可以这样做:


MyClass nestobject = new MyClass
{
  Name = "yy",
  Number = "1111",
  oclassMember = new OClass
  {
    addr = "neijiang",
    zip = "404045"
  }
};

使用了这么多,需要注意的也还是有:
  自动属性中,get和set后都有分号,花括号后边没有,二在对象初始化器的使用中,花括号中对各个属性赋值时用逗号隔开,花括号结束了用分号。本质原因,自动属性是属性定义,按C# 2.0语法,get和set分别相当于一个语句,花括号相当于方法的开始和结束。而使用对象初始化器,相当于使用花括号来调用其构造函数,整个new的过程相当于一条语句。
  在使用对象初始化器设置嵌套的属性类型的时候,内层嵌套的属性用对象初始化器后的花括号后也是用逗号,而不是用分号。如果这嵌套的属性放在了最后,则不用,如上例。

不管是嵌套的属性,或者不嵌套的属性,或者被嵌套的属性,使用对象初始化器,要去该对象所属的类必须提供没有参数的构造函数,否则会报错:does not contain a constructor that takes '0' arguments。
  使用对象初始化器时,花括号中对属性赋值的顺序可以交换,如:

MyClass nestobject1 = new MyClass
{
  Name = "yy",
  oclassMember = new OClass
  {
    addr = "neijiang",
    zip = "404045"
  },
  Number = "1111"
};
也是对的。


三、将对象初始值设定项用于匿名类型
  查询表达式经常使用匿名类型,而这些类型只能使用对象初始值设定项进行初始化。如:

MyClass[] ojbset = new MyClass[12];
var vaobj =
  from obj in ojbset
  select new { obj.Name, obj.Number };
也就是说,把objset中的每一个obj的Name属性和Number属性拿来,new成新隐式类型,赋值给vaobj,这种新类型的属性名也被省略掉了,那实际上,其属性名就是Name和Nnumber,值分别是它们两者的值。这个方式呢,由于new { obj.Name,obj.Number };这句是new的一个新的隐式类型,与类MyClass没有关系,所以,MyClass没有无参构造函数也是可以的。而如果要在new隐式类型的时候,重新命名其属性,则可以采用如下方式:

var varobj =
  from vobj in ojbset
  select new { vobj.Name, ID = vobj.Number };

四、集合初始值设定项
  集合初始值设定项,也叫集合初始化器,会对初始化器中的元素进行按序调用ICollection<T>.Add(T) 。使用集合初始值设定项的对象的类型必须实现了System.Collections.Generic.ICollections<T>接口并指定了确定的T。使用它可以在初始化一个实现了IEnumerable的集合类时指定一个或多个元素初始值;
  元素初始值设定项可以是简单的值,也可以是表达式或对象初始值设定项;
  通过使用集合初始值设定项,无需在源代码中指定多个对该类的Add 方法的调用;编译器会添加这些调用。
  例子如下:

public void setinit()
{
  List<int> digits = new List<int> {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  };
  List<int> digits2 = new List<int> {
    0 + 1, 12 % 3, getIntNumber()
  };
  List<MyClass> customers = new List<MyClass>{
    new MyClass{Number="1111",Name="yy"},
    new MyClass{Number="2222",Name="qq"},
    new MyClass{Number="3333",Name="qiqi"}
  };
}
public int getIntNumber()
{
  return 56;
}

这和以前调用List.Add没有本质的区别,编译器自动的调用了List的无参构造方法,然后实例化一个个的MyClass,再一个个的Add进去,和我们原来的做法没有什么不同,但是,这是编译器在后台自动处理,简省了我们很多的编码工作。
  注:
  各项之间还是用逗号,结束了,花括号后边表示new这个集合结束,用分号。
  如果集合的Add 方法允许,可以将null 指定为集合初始值设定项中的一个元素。如:

List<MyClass> customers = new List<MyClass>{
  new MyClass{Number="1111",Name="yy"},
  new MyClass{Number="2222",Name="qq"},
  new MyClass{Number="3333",Name="qiqi"},
  null
};

五、总结
  这些新特性平常怕是很少用到的,因为已经习惯了C# 2.0的写法,而且,这样写又不是必须的。但真正熟悉了,编译器已经帮开发人员做了越类越多的工作,从而节约了我们的开发时间。或许,在其它的应用当中,这样的语法还能用的到吧。


来源: 博客园   作者:山高月大

;