Возможные ловушки использования этого (основанного на методе расширения) сокращения

C#6 Update

ВС # 6?. is now a language feature:

// C#1-5
propertyValue1 = myObject != null ? myObject.StringProperty : null; 

// C#6
propertyValue1 = myObject?.StringProperty;

Вопрос ниже по-прежнему относится к более старым версиям, но при разработке нового приложения с использованием нового?. Оператор гораздо лучшая практика.

Original Question:

Я регулярно хочу получить доступ к свойствам на возможно нулевых объектах:

string propertyValue1 = null;
if( myObject1 != null )
    propertyValue1 = myObject1.StringProperty;

int propertyValue2 = 0;
if( myObject2 != null )
    propertyValue2 = myObject2.IntProperty;

И так далее...

Я использую это так часто, что у меня есть фрагмент для этого.

Вы можете сократить это до некоторой степени встроенным, если:

propertyValue1 = myObject != null ? myObject.StringProperty : null;

Однако это немного неуклюже, особенно если задано много свойств или если несколько уровней могут быть нулевыми, например:

propertyValue1 = myObject != null ? 
    (myObject.ObjectProp != null ? myObject.ObjectProp.StringProperty) : null : null;

Что я действительно хочу, так это?? синтаксис стиля, который отлично работает для напрямую нулевых типов:

int? i = SomeFunctionWhichMightReturnNull();
propertyValue2 = i ?? 0;

Итак, я придумал следующее:

public static TResult IfNotNull<T, TResult>( this T input, Func<T, TResult> action, TResult valueIfNull )
    where T : class
{
    if ( input != null ) return action( input );
    else return valueIfNull;
}

//lets us have a null default if the type is nullable
public static TResult IfNotNull<T, TResult>( this T input, Func<T, TResult> action )
    where T : class
    where TResult : class
{ return input.IfNotNull( action, null ); }

Это позволяет мне использовать этот синтаксис:

propertyValue1 = myObject1.IfNotNull( x => x.StringProperty );
propertyValue2 = myObject2.IfNotNull( x => x.IntProperty, 0);

//or one with multiple levels
propertyValue1 = myObject.IfNotNull( 
    o => o.ObjectProp.IfNotNull( p => p.StringProperty ) );

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

Этот пример довольно простой, чуть более сложный, если сравнивать два свойства объекта, допускающие обнуляемость:

if( ( obj1 == null && obj2 == null ) || 
    ( obj1 != null && obj2 != null && obj1.Property == obj2.Property ) )
    ...

//becomes
if( obj1.NullCompare( obj2, (x,y) => x.Property == y.Property ) 
    ...

Каковы недостатки использования расширений таким образом? Другие кодеры могут быть сбиты с толку? Это просто злоупотребление расширениями?

Я думаю, что я действительно хочу здесь, это расширение компилятора / языка:

propertyValue1 = myObject != null ? myObject.StringProperty : null;

//becomes
propertyValue1 = myObject?StringProperty;

Это значительно усложнит сложный случай:

propertyValue1 = myObject != null ? 
    (myObject.ObjectProp != null ? myObject.ObjectProp.StringProperty) : null

//becomes
propertyValue1 = myObject?ObjectProp?StringProperty;

Это будет работать только для типов значений, но вы можете вернуть обнуляемые эквиваленты:

int? propertyValue2 = myObject?ObjectProp?IntProperty;

//or

int propertyValue3 = myObject?ObjectProp?IntProperty ?? 0;

Ответы на вопрос(11)

Ваш ответ на вопрос