2014-12-04 3 views
5

Я хочу условно присвоить значение переменной, если эта переменная уже равна null. Более того, если эта переменная еще не null Я хочу, чтобы ничего не произошло, и я хочу иметь возможность делать все с одним оператором.Операция присваивания, которая ничего не делает, если переменная равна нулю?

object a = null; 
object b = new Something(); 

// this is essentially what I want but done with an operator: 
if(a == null) 
{ 
    a = b; 
} 

// this is all I feel I have to work with, 
a = a || b; 
a = a ?? b; 
a = a == null ? b : a; 

// the above methods all end up performing a = a if a is not null 
+5

Поэтому я предполагаю, что 'a = a ?? b; 'отсутствует? –

+1

@JoelRondeau Появляется так - OP не хочет, чтобы 'a' был привязан к себе. –

+0

'if (a == null) a = b;' Если вы не хотите, чтобы 'a' был назначен обратно на' a', вам, вероятно, придется использовать оператор 'if'. – heavyd

ответ

6

Если вы обеспокоены тем, что все это делается в одном заявлении, вам не повезло - C# не имеет этой функции на лингвистическом уровне и не поддерживает объявление оператора (как и F #) или перегрузка оператора присваивания (как и C++). Однако есть несколько вариантов, если они не настолько элегантны, как вы просили.

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

if(a == null) a = b; 

вспомогательный метод, который использует параметр, ref

public void AssignIfNull<T>(ref T target, T value) 
{ 
    if(target == null) target = value; 
} 

// ... 

AssignIfNull(ref a, b); 

Примечание выше будет не работа с Имуществом, поскольку они не могут быть переданы как параметр ref.

РЕДАКТИРОВАТЬ: В то время как выше, похоже на Interlocked.CompareExchange, такая альтернатива возвращает оригинального значения первого параметра, так что это может оказаться больше, чем Gotcha реализации описанного выше способом.

Или вы можете тщательно переписать свой первоначальный оператор для использования оператора нулевой коалесценции (??) в исходном назначении.

3

Как вы сказали, заявление if - это то, что вам нужно. Условный оператор не назначается, если null. В этом случае наиболее подходящим является if (не все должно быть oneliner).

Лучшие варианты:

if(a == null) 
{ 
    a = b; 
} 

Или:

a = a ?? b; 

На самом деле, я считаю, что последний оптимизирован прочь как простое if заявление.

Назначение a само по себе неплохо. С объектными ссылками это просто назначение адреса памяти. Для типов значений это всего лишь небольшой фрагмент данных.

Если a на самом деле это свойство сеттер, проверить внутри сеттера значение имеет изменения:

private string a; 

public string A 
{ 
    get 
    { 
     return a; 
    } 
    set 
    { 
     if (value != a) 
     { 
      a = value; 
     } 
    } 
} 
+1

Действительно ли 'a = a' запускает метод' set' объекта? Я действительно не хочу, чтобы это срабатывало. – LCIII

+0

О, извините, мой плохой. :) – Andrew

1

Хотя синтаксис многословен

(a==null?()=>a=b:(Action)(()=>{}))(); 

Давайте разбить его на части

(       // Expression starts here 
    a == null    // If a == null... 
     ?() => a = b  // return lambda that assigns a = b 
     : (Action) (  // Else return next lambda casted as Action 
      () => {}  // Empty lambda that does nothing 
     )     // End cast 
)       // Expression ends here 
();       // Execute it! 

Во всяком случае, я бы просто использовал один вкладыш, если if(a == null) { a = b; }

+2

Почему downvote? это делает именно то, что задал ОП –

+2

Я не спустил вниз, но это всего лишь неясный способ сделать 'if'. На самом деле '?' Делает это. –

+0

Разница в том, что? возвращает выражение, которое должно быть присвоено некоторой переменной. единственный способ избавиться от этой переменной - заставить его возвращать lambdas и выполнять его как функции самообучения javascript. –

1

В качестве одного оператора,

var result = ((a == null) ? (a = b) : null); 

Значение result затем может быть отброшен. Имея a и b в качестве свойств объекта, а добавление Console.WriteLine() в настройке для a покажет, что оно назначено только тогда, когда оно было ранее null.

Единственное, что останавливает его, как чистое, заключается в том, что создается переменная result; надеюсь, он по-прежнему достаточно чист.


Добавление - Я просто понял, что вы также можете использовать:

var result = a ?? (a = b); 

как еще более короткой версии выше. Опять же, a = b оценивается только в том случае, если a - null.

2

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

Дело 1: Инициализация. Используя свои значения из выше, это становится:

object a = null ?? something; 

Очевидно, что я не стал бы писать эту строку кода (ReSharper будет жаловаться, если ничего другого). Но это суть происходящего. Если у меня есть два (или более) значения, доступные при создании a, тогда я пишу его вот так.

Корпус 2: Никогда не устанавливайте a, но используйте ??, когда используется a. В этом случае код будет:

MethodTakingA(a ?? b); 

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

Существует третий случай, когда я выполняю точное задание, которого вы избегаете. То есть, когда один из параметров моего метода может быть нулевым, и у меня есть значение по умолчанию, которое нужно использовать в этом случае (вместо того, чтобы бросать ArgumentNullException). Вот пример:

public void Foo(string str) 
{ 
    str = str ?? String.Empty; 
    //Use str as needed below without fear that it might be null. 
} 

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

string localStr = str ?? String.Empty; 

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

Смежные вопросы