Лучшее / самое близкое к тому, что вы после этого я мог придумать, это:
_ = condition ? (a = c) : (b = c);
В контексте:
bool condition = true;
int a = 1;
int b = 2;
int c = 3;
_ = condition ? (a = c) : (b = c);
Console.WriteLine($"a = {a}; b = {b}; c = {c}");
Выходы
a = 3; b = 2; c = 3
Объяснение
_ =
требуется, поскольку троичный оператор доступен, только если мы назначаем что-то. Здесь мы используем _
в качестве переменной discard; то есть нас не волнует возвращаемое значение; только то, что сама операция происходит.
использование скобок (например, (a = c)
требуется вокруг назначения, так как нам нужно вернуть результат. Выполнение a = c
присваивает значение c
a
, но ничего не возвращает вызывающий. (a = c)
, с другой стороны, присваивает c
a
, а затем выводит новое значение a
, делая его доступным в контексте остальной части метода, т. е. Aisde из присваиваний этого оператора эффективно читает _ = condition ? c : c;
.
- Все остальное как и следовало ожидать от стандартного троичного оператора. Тем не менее, любые вопросы, пожалуйста, скажите.
Мысли
Это не идеально, так как вы должны указывать каждое назначение отдельно; но дает вам стенографию ...
Я подозреваю, что в обзоре кода это, как правило, не одобряется, поскольку он менее читабелен, чем стандартный подход if / else ...
NB. В некоторых других языках можно использовать хитрость, заключающуюся в том, чтобы условие выступало в качестве индекса для массива (например, false = 0, true = 1), а затем использовало его при присвоении значения ... Однако, хотя вы можете заставить это сделать в C #, это не красиво:
void Main()
{
bool condition = true;
var a = new ReferenceType<int>(1);
var b = new ReferenceType<int>(2);
var c = new ReferenceType<int>(3);
(new []{b, a})[ConvertBoolToInt(condition)].Value = c.Value;
Console.WriteLine($"a = {a}; b = {b}; c = {c}");
}
//in C# bools aren't natively convertable to int as they are in many langauges, so we'd need to provide a conversion method
public int ConvertBoolToInt(bool value)
{
return value ? 1 : 0;
}
//to allow us to change the value rather than only the refenence, we'd need to wrap our data in something and update the value assigned to its property
public class ReferenceType<T>
{
public T Value {get;set;}
public ReferenceType(T intValue)
{
Value = intValue;
}
public override string ToString()
{
return Value.ToString();
}
}
Тем не менее, вышеизложенное говорит о создании более общего подхода ... Если ваш вариант использования ограничен назначением оружия / аналогичными сценариями использования, вы можете использовать аналогичный прием, такой как этот:
public enum WeaponHandEnum
{
Primary //int = 0
,
Secondary //int = 1
}
public class Player
{
public Weapon[] Weapons {get;set;}
public Player(Weapon primary = null, Weapon secondary = null)
{
Weapons = new Weapon[2] {primary, secondary};
}
public void Equip(WeaponHandEnum whichHand, Weapon newWeapon)
{
Weapons[(int)whichHand] = newWeapon;
}
}
public class Weapon{ /* ... */ }
Если вы обнаружите, что вам приходится делать много таких утверждений в коде, и вы хотите, чтобы ваш счетчик строк находился в обратном порядке, вам лучше всего что-то вроде этого:
void Main()
{
bool condition = true;
var a = 1;
var b = 2;
var c = 3;
SomeKindaHelper.TernaryAssign<int>(condition, ref a, ref b, c);
Console.WriteLine($"a = {a}; b = {b}; c = {c}");
}
public static class SomeKindaHelper
{
public static void TernaryAssign<T>(bool condition, ref T assignToMeIfConditionIsTrue, ref T assignToMeIfConditionIsFalse, T newValue)
{
if (condition)
{
assignToMeIfConditionIsTrue = newValue;
}
else
{
assignToMeIfConditionIsFalse = newValue;
}
}
}
т.е. Хотя это несколько строк кода для определения вспомогательного метода, вы можете использовать его повсеместно как один слой, и он будет гораздо более читабельным, если не таким умным.