使用扩展方法对调用进行验证

  • 张逸

2009 年 3 月 27 日

话题:.NET编程语言C#语言 & 开发架构

利用 C# 3.0 提供的扩展方法技术,可以为已经编译好的程序集类型增加新的方法,从而应对新的扩展。除了在可扩展性方面所具有的优势之外,如果能够合理地结合泛型与类型推断,扩展方法还可以有效降低代码的重复,提高程序的可重用性。例如,这样的方法实现:

public class CustomerDAL

{

    public IEnumerable FindCustomers(string roleName)

    {

        return from customer

             in context.Customer

             where customer.RoleName.Equals(roleName)

             select customer;

    }

}

调用如下方法,可能抛出 NullReferenceException 异常:



Customer customer = new CustomerDAL().FindCustomers(Role.Admin).First();

我们需要对返回结果进行验证,如果返回为 null,则可以抛出自定义异常,或者创建一个空对象,例如:



public IEnumerable FindCustomers(string roleName)

{

    IEnumerable 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(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(this T obj) where T:new()

{

    if (obj == null)

    {

        obj = new T();

    }

    return obj;

}

由于 Instance 扩展方法中的类型参数 T 需要创建实例,因此必须添加 new() 约束。所以该扩展方法存在一定的局限,例如无法应用在之前的 IEnumerable类型上。但对于如下的方法却非常有效:

public class ListObject

{

    public List Foo()

    {

        return null;

    }

}

通过 Instance 扩展方法,可以安全地调用 List的相关属性和方法,例如 Count 属性:

Console.WriteLine(new ListObject().Foo().Instance().Count);

控制台打印出来的结果为 0。如果没有 Instance 扩展方法,则会抛出 NullReferenceException 异常。

作为 C# 3.0 增加的新特性,扩展方法在大量项目中得到了广泛地应用,但绝不仅仅是提高可扩展性这么简单。在进行项目开发时,若能适当地考虑使用扩展方法,说不定会带来出奇制胜的效果。

.NET编程语言C#语言 & 开发架构