扩展方法代替Null对象模式

时间:2008-11-15 13:45:31

标签: c# .net null extension-methods

我想知道使用扩展方法来避免在层次结构中检查null。 例子:

// GetItems(), GetFirstOrDefault(), GetProduct(), GetIDProduct() are extension methods like:
public static SomeType GetSomeProperty( this XYZ obj ) {
    if ( object.ReferenceEquals( obj, null ) ) { return default( SomeType ); }
    return obj.SomeProperty;
}

// the code with extension methods
Guid? idProduct = this.Invoice.GetItems().GetFirstOrDefault().GetProduct().GetIDProduct();
// instead of
Guid? idProduct = null;
Invoice invoice = this.Invoce;
if ( null != invoice ) {
    InvoiceItems items = invoice.Items;
    if ( null != items && items.Count > 0 ) {
        InvoiceItem item = items[0];
        if ( null != item ) {
            idProduct = item.IDProduct();
        }
    }
}

我知道,有可用的Null Object模式,但使用这种扩展方法的解决方案看起来更好。

你认为,这个解决方案是好还是坏(因为糟糕/好的设计,清晰度,还有其他什么)?

请投票“好”或“坏”,为什么这么认为。 帖子被夸大为社区。

5 个答案:

答案 0 :(得分:2)

我只是理智地做到了:

Guid? idProduct = null;
Invoice invoice = this.Invoce;

if (invoice != null && 
    invoice.Items != null &&
    invoice.Items.Count > 0 &&
    invoice.Items[0] != null) 
{
   idProduct = invoice.Items[0].IDProduct();
}

答案 1 :(得分:1)

实例方法的breaks the semantics。扩展方法看起来像调用者的实例方法,因此行为就像它们一样。当你破坏这样的语义时,代码将更难理解和维护,其行为将使大多数开发人员感到惊讶。

答案 2 :(得分:1)

我将此投票为“不感兴趣的解决方案”。

我的实体模型类的Null-Object-Pattern很好。

答案 3 :(得分:0)

阅读此代码时,第一件事让我印象深刻

GetFirstOrDefault().GetProduct()

它打破了两个习语:1)使用Jon指出的Get样式方法,以及2)“取消隐藏”Null Object提供的抽象。 OrDefault让我作为您代码的读者,让我思考null其中

GetFirst().GetProduct()

不会。是的,Null Object的一个要点和你的扩展方法替代方案是解除读者和/或维护者的负担。或者为什么要么?

答案 4 :(得分:0)

Java和.net的一个限制是,没有什么可以清楚地识别引用类型的存储位置是否应该在语义上被视为持有对象的值,而标识一个对象(当然,从计算机的角度来看,所有这些存储位置都是后者)。尽管如此,有些类型(如String)通常会将存储位置视为保留值,而其他类型(如StringBuilder)则将存储位置视为标识对象应该在哪些操作上进行。

如果不是struct上的Nullable<T>约束,并且类型类型可以指定在空对象上调用时实例成员应该运行(this为空),我会认为这是某些类型的优秀模式。虽然通常不可能合理地为可变类类型指定默认值,但对于许多不可变类型而言,具有合理的默认行为(例如default(string).Length可能返回零)将是完全合理的。不幸的是,.net语言没有办法指定属性和方法应该可以在null对象上使用,但至少扩展方法可以在这个方向上做一些帮助。