使用扩展方法对调用进行验证
发布:张逸 | 发布时间: 2009年3月28日利用C# 3.0提供的扩展方法技术,可以为已经编译好的程序集类型增加新的方法,从而应对新的扩展。除了在可扩展性方面所具有的优势之外,如果能够合理地结合泛型与类型推断,扩展方法还可以有效降低代码的重复,提高程序的可重用性。例如,这样的方法实现:
public class CustomerDAL
{
public IEnumerable<Customer> FindCustomers(string roleName)
{
return from customer
in context.Customer
where customer.RoleName.Equals(roleName)
select customer;
}
}
当方法返回的结果为null时,采用如下方式进行调用,就会抛出NullReferenceException异常:
Customer customer = new CustomerDAL().FindCustomers(Role.Admin).First();
我们需要对返回结果进行验证,如果返回为null,则可以抛出自定义异常,或者创建一个空对象,例如:
public IEnumerable<Customer> FindCustomers(string roleName)
{
IEnumerable<Customer> customers = from customer
in context.Customer
where customer.RoleName.Equals(roleName)
select customer;
if (customers == null)
{
throw new MyException("Cann't find the customers.");
}
return customers;
}
如果系统有许多方法都需要对返回结果进行验证,则这样的验证逻辑就会充斥在各个方法体中,既不利于重用,也会对未来的修改造成极大的阻碍。当然,我们可以引入Null Object模式来替代对null值的判断逻辑,但这种方式仍然需要为多种类型定义不同的Null Object类型。
Craig Andera在其博客文章中提出使用扩展方法对调用进行验证。他写道:
NullReferenceException异常会抛出,但是我们希望有更具体的异常信息。因此,我们编写了如下的扩展方法:
public static T OrThrow<T>(this T obj, Exception e) {
if (obj == null) {
throw e;
}
return obj;
}
利用OrThrow扩展方法,则之前的调用方式可以修改为:
Customer customer = new CustomerDAL().FindCustomers(Role.Admin).OrThrow(new MyException("Can't find Customer")).First();
Craig Andera提出:
OrThrow扩展方法对于你所要调用的类型而言是通用的,并且它返回了该类型,所以你可以将其插入到表达式链中,而不会丢失智能感应功能。并且因为类型推断功能,实际上并不需要指定具体的类型。
也就是说,OrThrow扩展方法可以应用到任何类型上,因此它可以在各种类型上重用非空验证甚至是调用验证。借鉴这一思想,我们还可以利用此方法默认实现对象实例的创建,以避免抛出NullReferenceException异常,例如:
public static T Instance<T>(this T obj) where T:new()
{
if (obj == null)
{
obj = new T();
}
return obj;
}
由于Instance扩展方法中的类型参数T需要创建实例,因此必须添加new()约束。所以该扩展方法存在一定的局限,例如无法应用在之前的IEnumerable类型上。但对于如下的方法却非常有效:
public class ListObject
{
public List<string> Foo()
{
return null;
}
}
通过Instance扩展方法,可以安全地调用List的相关属性和方法,例如Count属性:
Console.WriteLine(new ListObject().Foo().Instance().Count);
控制台打印出来的结果为0。如果没有Instance扩展方法,则会抛出NullReferenceException异常。
作为C# 3.0增加的新特性,扩展方法在大量项目中得到了广泛地应用,但绝不仅仅是提高可扩展性这么简单。在进行项目开发时,若能适当地考虑使用扩展方法,说不定会带来出奇制胜的效果。
本文在InfoQ中文站发表:使用扩展方法对调用进行验证
- 相关文章:
.Net编码技巧与资源 (2009-3-22 21:21:0)
Builder模式应用实践 (2009-3-18 15:39:56)
Martin Fowler确定QCon北京演讲 (2009-3-9 12:5:13)
在Dictionary中使用枚举 (2009-3-7 21:20:49)
当弱引用对象成为集合元素时 (2009-3-4 21:1:55)
C#中的结构与类 (2009-3-3 15:13:17)
QCon北京演讲题目 (2009-3-3 13:21:51)
QCon全球企业开发大会(北京)即将拉开帷幕 (2009-2-14 12:52:25)
泛型的一点遗憾 (2009-2-14 9:48:21)
- 1.gattaca
- 目前手上有許多用Socket溝通的工廠硬體(Tcp,Udp都有),
請問WCF能與這些Socket溝通嗎?
這些硬體設備所發的Socket都不含soap訊息的...
我在msdn論壇看到一篇用WCF模擬低層Socket的文章,
但是實際使用卻是有問題的...
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/d7079064-72a8-4288-9500-216db523a864/张逸 于 2009-4-4 13:36:02 回复我想,WCF与Socket设备的通信是没有问题的。WCF使用的NetTcpBinding,其底层实际上就是使用Socket通信机制。不过,我对此确实没有研究,真还不知具体该如何实现。但我感觉WCF使用的编码方式不一定是SOAP,序列化格式器中,我们可以选择其他的编码方式,例如二进制。 - 2009-4-2 13:58:24 回复该留言
- 3.gattaca
- 抱歉!! 忘了用Word转换
=====================================
目前手上有许多用Socket沟通的工厂硬件(Tcp,Udp都有),
请问WCF能与这些Socket沟通吗?
这些硬设备所发的Socket都不含soap讯息的...
我在msdn论坛看到一篇用WCF模拟低层Socket的文章,
但是实际使用却是有问题的...
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/d7079064-72a8-4288-9500-216db523a864/
============================================== - 2009-4-3 16:41:29 回复该留言
- 5.loudouzi
- 按照以前的方法,“则这样的验证逻辑就会充斥在各个方法体中”
但按照这个方法,每次调用都带上“OrThrow(new MyException("Can't find Customer"))”,岂不更恐怖?
博主这个方法究竟有没有实践检验过啊?张逸 于 2009-6-19 11:03:12 回复这样看你怎么看了。其实我觉得我后面增加的Instance<T>()更有用。Craig Andera提供的OrThrow()方法确实存在你说的问题。 - 2009-6-17 18:25:01 回复该留言
发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。






张逸(Bruce Zhang)
