Обновление С# 6
В С# 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;