有没有办法使用三元运算符 - 或类似的方法 - 来选择要分配给的变量?

Is there a way to use a ternary operator - or similar method - for picking the variable to assign to?

是否可以根据条件改变我分配给的变量?我遇到的问题是想这样做:

(bEquipAsSecondary ? currentWeaponOffhand : currentWeaponMainhand) = weaponToSwitchTo;

而不是

if (bEquipAsSecondary)
{
    currentWeaponOffhand = weaponToSwitchTo;
}
else
{
    currentWeaponMainhand = weaponToSwitchTo;
}

导致以下错误

Error CS0131 The left-hand side of an assignment must be a variable, property or indexer

所以我想知道是否有一种方法可以减少 space 的使用,并且 - 在我看来 - 让它看起来更整洁?

不确定三元运算符是否比此处的常规 if-else 语句更好。但是你可以使用 Action,像这样:

(bEquipAsSecondary ? new Action(() => currentWeaponOffhand = weaponToSwitchTo)
                   : () => currentWeaponMainhand = weaponToSwitchTo)();

要使用三元运算符来选择要为其赋值的变量,您可以使用 ref locals/returns。例如,

(bEquipAsSecondary ? ref currentWeaponOffhand : ref currentWeaponMainhand) = weaponToSwitchTo;

示例输出和代码

var currentWeaponOffhand = 4;
var currentWeaponMainhand = 5;
var weaponToSwitchTo = 7;

(bEquipAsSecondary ? ref currentWeaponOffhand : ref currentWeaponMainhand) = weaponToSwitchTo;
Console.WriteLine($"When bEquipAsSecondary={bEquipAsSecondary},currentWeaponOffhand={currentWeaponOffhand},currentWeaponMainhand={currentWeaponMainhand}");

输出

When bEquipAsSecondary=False,currentWeaponOffhand=4,currentWeaponMainhand=7
When bEquipAsSecondary=True,currentWeaponOffhand=7,currentWeaponMainhand=5

我能想到的最好/最接近你想要的是:

_ = 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"变量;即我们不关心 returned 值;只有操作本身发生。

  • 使用括号(例如 (a = c) 需要围绕赋值,因为我们需要 return 结果。执行 a = c 赋值 ca,但不会 return 给调用者任何东西。另一方面,(a = c)c 分配给 a,然后输出新值a,使其在方法的其余部分的上下文中可用。即 Aisde 从作业中该语句有效读取 _ = condition ? c : c;.

    • 其他一切都如您对标准三元运算符所期望的那样。不过,有什么问题,请说。

想法

这并不理想,因为您必须分别指定每个分配;但确实给你一种形式 shorthand...

我怀疑这在代码审查中通常会被反对,因为它的可读性不如标准 if/else 方法...


注意:在其他一些语言中,可以使用的技巧是让条件充当数组的索引(例如 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;
        }
    }
}

即虽然这是定义辅助方法的几行代码,但您可以将它作为一个衬里在所有地方重复使用,而且它的可读性要高得多,即使不是那么聪明。

您可以使用三元运算符选择一个操作来更新正确的插槽。

//Define action to equip appropriate slot
var equipAction = bEquipAsSecondary
    ? new Action<Weapon>( w => currentWeaponOffhand = w )
    : new Action<Weapon>( w => currentWeaponMainhand = w );

//Now equip the weapon
equipAction(weaponToSwitchTo);