Метод расширения вместо шаблона Null Object - PullRequest
3 голосов
/ 15 ноября 2008

Мне интересно использовать метод расширения, чтобы избежать проверки на ноль в иерархии. Пример:

// 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 ]

2 голосов
/ 15 ноября 2008

Я бы просто сделал это разумно:

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 голос
/ 04 февраля 2010

Я голосую за это как "не заинтересованное в этом решении".

Я в порядке с Null-Object-Pattern для моих классов модели сущностей.

1 голос
/ 04 февраля 2010

Это нарушает семантику метода экземпляра. Методы расширения выглядят как методы экземпляра для вызывающих, и поэтому должны вести себя как они. Когда вы нарушите подобную семантику, код будет сложнее понять и поддерживать, его поведение удивит большинство разработчиков.

0 голосов
/ 03 октября 2012

Одно ограничение для Java и .net состоит в том, что нет ничего, что бы четко определяло, следует ли семантически рассматривать место хранения ссылочного типа как , содержащее значение объекта, по сравнению с , идентифицирующим объект (с точки зрения компьютера, конечно, все такие места хранения делают последнее). Тем не менее, есть некоторые типы (например, String), для которых место хранения обычно рассматривается как содержащее значение, а другие (например, StringBuilder), для которых место хранения будет рассматриваться как идентифицирующий объект, над которым должны выполняться операции. быть выполненным.

Если бы не ограничение struct для Nullable<T>, и если типы классов могли бы указывать, что члены экземпляра должны запускаться (при this, равном нулю) при вызове для нулевого объекта, я бы расценил это как превосходное шаблон для некоторых типов. Хотя обычно невозможно разумно указать значение по умолчанию для изменяемого типа класса, для многих неизменяемых типов вполне разумно иметь разумное поведение по умолчанию (например, default(string).Length может возвращать ноль). К сожалению, языки .net не имеют возможности указать, что свойства и методы должны использоваться на нулевых объектах, но по крайней мере методы расширения могут немного помочь в этом направлении.

0 голосов
/ 25 октября 2011

Первое, что поразило меня при чтении этого кода, было

GetFirstOrDefault().GetProduct()

Это нарушает две идиомы: 1) использование методов стиля Get, как отметил Джон, и 2) «скрытие» абстракции, предоставленной Null Object. OrDefault привлекает меня как читателя вашего кода и заставляет меня думать о null, где

GetFirst().GetProduct()

не будет. И да, одна из точек Null Object и альтернативы вашему методу расширения состоит в том, чтобы освободить читателя и / или сопровождающего. Или еще зачем?

...