C# 3.0的自动生成的属性

之前在[url=http://rednaxelafx.iteye.com/blog/177092]将ANTLR生成的.tokens文件重格式化(C#版)[/url],我把一个简单的对文本文件的匹配和排序程序用C#实现出来,并且与同系列文章中的Ruby和C++实现做了对比。当时我用到了C# 3.0的一些新特性来展现C#的简洁性,例如Lambda表达式之类。不过最近在读Jon Skeet编写、Manning出版的[i]C# in Depth[/i]一书时发觉C# 3.0还有个很好的功能:自动生成的属性。

在用Java或者C#写程序的时候,许多guideline都建议不要直接暴露对象内部状态的变量,而是提供accessor/modifier(getter/setter)方法来提供对这些变量的访问。但有许多时候这些访问方法的逻辑是微不足道的(trivial),单纯就是把变量给包装了一下:
class Foo {
private String bar;

public String getBar() {
return this.bar;
}

public void setBar(String bar) {
this.bar = bar;
}
}

这种代码在POJO里十分常见但又没什么好办法避免。除非真的把域写成public的,但那样有潜在的缺陷就是了。

在C#里这个状况稍微好些,可以用专门的语法来把访问方法组织在一起,称为[b]属性[/b]:
class Foo {
private string _bar;

public string Bar {
get {
return _bar;
}
set {
_bar = value;
}
}
}

虽然写的代码稍微短了点,但这种没什么实际作用的代码还是占了很多行。

在C++/CLI里有自动生成的属性:
class Foo {
public:
property String^ Bar;
}

编译器会为这种属性自动生成一个私有变量来保存其状态,而不用我们手动指定。省了不少键盘输入,同时也减少了出错的机会。

Ruby对这种问题能通过元编程很好得解决:
class Foo
attr_accessor :bar

def initialize
@bar = ""
end
end


在C# 3.0中,这个问题终于也有类似C++/CLI的解决办法了:同样是自动生成的属性。只要写一个非抽象的省略了get和set方法体的属性,编译器就能自动生成一个私有变量来对应这个属性。
class Foo {
public string Bar { get; set; }
}

非常方便。并且,对get和set单独指定可访问性的能力依然存在。例如说如果某个属性对外是只读的,那么写成:
class Foo {
public string Bar { get; private set; }
}

就行。
注意到C# 3.0的自动生成的属性的语法:[b]必须同时指定get和set,而不能只写其中一个[/b]。因此能够单独指定可访问性的特点就非常重要了。

在处理ANTLR的.tokens文件那篇里,我定义了一个struct来保存数据:
struct TokenNameValuePair {
private string _name;
private int _value;

public TokenNameValuePair(string name, int value) {
_name = name;
_value = value;
}

public string Name { get { return _name; } }
public int Value { get { return _value; } }
}

这里的两个属性都很明显是trivial的,用自动生成的属性是最好不过了。换成这样:
class TokenNameValuePair { // notice the "class" keyword
public string Name { get; private set; }
public int Value { get; private set; }

public TokenNameValuePair(string name, int value) {
Name = name;
Value = value;
}
}

注意到我把原本定义为struct的这个类型改成class了。在C# 3.0中,自动生成的属性在struct中使用有个小小的诡异的地方:要在某个struct里使用自动生成的属性,所有构造器都必须调用无参数版本的构造器,这样编译器才能够确认所有的成员变量都被确定性赋值过。我们无法直接对自动生成的域赋值,因为不知道它的名字;而在所有的域都被赋值之前我们无法使用属性。
在这个例子里要继续使用struct的话,代码写成这样就行:
struct TokenNameValuePair {
public string Name { get; private set; }
public int Value { get; private set; }

public TokenNameValuePair(string name, int value) : this() { // calls this()
Name = name;
Value = value;
}
}


在Web开发的时候Model层里,许多纯粹的数据实体类的代码量都可以减少了……即便用代码生成器,生成出来的代码还是得维护,能有更简洁的语法总是件好事。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值