2016-07-08 4 views
61

Как написать стенографию следующего сценария?Есть ли сокращенный способ возврата значений, которые могут быть пустыми?

get 
{ 
    if (_rows == null) 
    { 
     _rows = new List<Row>(); 
    } 

    return _rows; 
} 
+14

Ваш код прекрасно, как есть. Это может быть сокращено, но за счет удобочитаемости. На мой взгляд, не стоит экономить 3 строки. –

+29

Я не сумасшедший об этом шаблоне. У вас есть getter, который производит изменение состояния –

+0

http: // stackoverflow.com/questions/13876066/is-it-bad-practice-to-have-my-getter-method-change-the-stored-value –

ответ

1
return _rows ?? (_rows = new List<Row>()); 
+3

или короче: return _rows == null? new List : _rows – nosbor

+3

@nosbor. Оба этих объекта продолжают возвращать новый экземпляр списка, поскольку они оставляют _rows неназначенными, что отличается от поведения, которое требует OP. – Andy

81

Используя null-coalescing operator (??):

get 
{ 
    _rows = _rows ?? new List<Row>(); 
    return _rows; 
} 

ИЛИ (менее читаемый):

get { return _rows ?? (_rows = new List<Row>()); } 

?? оператор называется нуль-коалесцирующим оператором. Он возвращает левый операнд , если операнд не равен нулю; в противном случае он возвращает правый операнд .

+20

возвращение _rows ?? (_rows = новый Список ()); – eocron

+1

Хорошо, поэтому вам удалось сделать код менее читаемым, в основном просто перебирая все вместе на одной строке в одном большом выражении, и вы не даете никакого объяснения, какое использование это может иметь. Без объяснения, я не вижу, как этот ответ полезен, по крайней мере, никому, кто заботится о написании кода, поддерживающего код. – hvd

+12

@ hvd документация, предоставленная для? более чем понятно. Я не вижу необходимости перефразировать ** clear ** документы своими словами. – user3185569

20

Я предлагаю тройной оператора

get { 
    return _rows == null ? _rows = new List<Row>() : _rows; 
} 

Или так пусто List<Row> не приносят много накладных расходов, почему бы не избавиться от явного _row поля и осуществлять только свойство только для чтения (C# 6,0 синтаксиса):

public IList<Row> Rows {get;} = new List<Row>(); 
+5

Решение C# 6 - это путь. –

+0

Для C# 6 я предпочитаю обычно добавлять новые в конструкторы для более легкой отладки. – Phil1970

5

Как это, например:

get{ return _rows ?? (_rows = new List<Row>()); } 
12
List<Row> _rows; 
public List<Row> Rows => _rows ?? (_rows = new List<Row>()); 
0

Если вы действительно хотите, чтобы сократить его, я бы просто удалить лишние скобки.

get 
    { 
     if (_rows == null) 
      _rows = new List<Row>(); 

     return _rows; 
    } 
+2

лучше не, действительно – edc65

+3

Я не уверен, почему это происходит. Конечно, на самом деле это не делает ничего, кроме сокращения исходного кода, но все же. Удаление фигурных фигурных скобок из высказываний одного утверждения, если многие из них считаются хорошими. –

+0

@MrLister На самом деле это не лучше. Это тот же код. –

10

Как уже говорилось, вы можете использовать оператор нулевого коалесцирования в этом сценарии.

get 
{ 
    return _rows ?? (_rows = new List<Row>()); 
} 

Стоит отметить, что это такое изменение, что ReSharper велик на предлагая (они называют это quick-fix).

В вашем примере он помещает небольшую кривую под оператором if. Наведение на него показывает suggestion, как можно было изменить/упростить код.

Convert to '??' expression

пару кликов позже, а изменение реализуется.

enter image description here

41

Это ленивый шаблон инициализации так простой способ будет использовать Lazy<T> класс.

class Foo 
{ 
    Lazy<List<Row>> _rows; 

    public Foo() 
    { 
     _rows = new Lazy(() => new List<Row>()); 
    } 

    public List<Row> Rows 
    { 
     get { return _rows.Value; } 
    } 
} 

Это дополнительное преимущество, что оно не «загрязняет» геттер логикой инициализации.

+1

Хотя создание списка настолько дешево, что это глупо. – CodesInChaos

+3

Я пошел с тем, что использовал ОП в его вопросе. Я предположил, что это всего лишь пример, и фактический объект более тяжелый. –

18

Вот еще одна идея: Предотвратить _rows от ever null.

Сделайте конструктор инициализации переменной:

public MyClass() 
{ 
    this._rows = new List<Row>(); 
} 

, а затем ваша собственность просто

get 
{ 
    return this._rows; 
} 

Убедитесь, что, если вам нужно «очистить» переменную, вы всегда называть его Clear или назначить новый пустой список вместо назначения null. Может быть, кодировать эту операцию в методе, если вам действительно нужно сделать ее понятной и последовательной во всем классе.

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

+3

В случае пустого списка, подобного здесь, нет большой разницы. Однако это не всегда верно в целом. Что делать, если инициализация объекта занимает больше времени, и вы (как автор библиотеки) не уверены, когда-либо запрашивается вызывающей программой. Тогда этот метод будет вводить слишком много накладных расходов, а ленивая загрузка - это путь. –

+0

Упрощение лучше. Пользователям никогда не нужно проверять значение null, и вам не нужно документировать его. По крайней мере, для List (я согласен с Lister), а для первой версии, если вы не знаете иначе, скорее всего, это преждевременная оптимизация (или что-то автоматическое может сделать для вас). Не тратьте время на размышления об этом. – toddkaufmann

+0

@MrLister Если вам нужна ленивая загрузка из-за некоторых служебных накладных расходов, то этот вопрос выбрал плохо, чтобы заменить его пустой инициализацией списка; более подходящим выбором будет что-то вроде «MyExpensiveToInitializeClass». Этот ответ относится к вопросу как написанный, и предполагает, что нет причин для этого, кроме того, что написано. Если есть, это будет другой вопрос. – jpmc26

3

Если вы хотите, чтобы ваш код вел себя как ваш текущий код, лениво инициализируя ваше фоновое поле при доступе к объекту, то да, вы можете сделать его короче. Вы можете переименовать поле подкладочный, как отвеченная уже используют ?? поместить все в одном выражении, и если у вас есть, что одно выражение, новый синтаксис свойств использование C# 6, чтобы избежать написания get и return:

List<Row>_;List<Row> Rows=>_??(_=new List<Row>()); 

Будем надеяться, что задолго до того, как вы дойдете до этого момента, вы увидите, что вы превратили простой в понимании код, который делает именно то, что вы хотите, в ужасный беспорядок, которого вы никогда не захотите поддерживать.

Просто сохраните свой код в точности так, как он есть. Вы можете сделать это короче, как показано, но это не делает его лучше.

Если проблема заключается в том, что для записи требуется больше времени, потому что вы продолжаете вводить один и тот же код снова и снова, многие IDE предоставляют некоторую функцию для вставки шаблонов, фрагментов или любого другого термина, который они используют для него. Это позволяет определить, что-то вдоль линий

{Type} {Field}; 
public {Type} {Property} { 
    get { 
    if ({Field} == null) { 
     {Field} = new {Type}(); 
    } 
    return {Field}; 
    } 
} 

где ваш редактор выдаст приглашение для конкретного типа {}, {поле}, {} Свойство, без необходимости вводить его каждый раз.

0

Вы можете сделать это любым из следующих способов:

  • Условный оператор (:)
  • Null-коалесцирующий оператор (??)

С Условный оператор

get { 
    return _rows == null ? new List<Row>() : _rows; 
} 

оператор Null-коалесцирующий

get { 
    return _rows ?? new List<Row>(); 
}