Обновление C # 6
In C # 6 ?.
теперь является языковой функцией :
// C#1-5
propertyValue1 = myObject != null ? myObject.StringProperty : null;
// C#6
propertyValue1 = myObject?.StringProperty;
Приведенный ниже вопрос по-прежнему относится к более старым версиям, но если разработка нового приложения с использованием нового оператора ?.
является гораздо более эффективной практикой.
Оригинальный вопрос:
Я регулярно хочу получить доступ к свойствам на возможно нулевых объектах:
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;