【问题标题】:Is there a way to use a ternary operator - or similar method - for picking the variable to assign to?有没有办法使用三元运算符 - 或类似的方法 - 来选择要分配的变量?
【发布时间】:2019-04-21 01:44:12
【问题描述】:

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

(bEquipAsSecondary ? currentWeaponOffhand : currentWeaponMainhand) = weaponToSwitchTo;

代替

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

这会导致以下错误

错误 CS0131 赋值的左侧必须是变量、属性或索引器

所以我想知道是否有办法做到这一点来减少使用的空间 - 在我看来 - 让它看起来更整洁一点?

【问题讨论】:

  • currentWeaponOffhandcurrentWeaponMainhand 的具体类型是什么?
  • 这些是类

标签: c# .net ternary-operator


【解决方案1】:

要使用三元运算符来选择要为其赋值的变量,您可以使用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

【讨论】:

  • 显然,您不需要var _ =
  • 不错的一个!虽然需要等待统一包含 C#7.2 才能使用 byref locals/returns
【解决方案2】:

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

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

【讨论】:

  • 我喜欢这个解决方案,因为它可以概括为一个框架来处理所有游戏动作的效果:你为每个可能的状态突变创建一个Action,然后游戏逻辑会计算出哪个@987654326 @ 从它的集合中需要被执行,并执行它。
【解决方案3】:

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

_ = 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

说明

  • _ = 是必需的,因为三元运算符仅在我们分配给某些东西时才可用。这里我们使用_作为“丢弃”变量;即我们不关心返回值;只是操作本身发生。

  • 使用括号(例如(a = c) 需要在赋值周围,因为我们需要返回结果。执行a = c 会将c 的值分配给a,但不会向调用者返回任何内容。另一方面,(a = c)c 分配给a,然后输出a 的新值,使其在方法的其余部分的上下文中可用。即,该语句有效地从分配中读取@987654334 @。

    • 其他一切都与您对标准三元运算符的期望相同。但是,有任何问题,请说。

想法

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

我怀疑这在代码审查中通常会被拒绝,因为它的可读性不如标准 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;
        }
    }
}

即虽然这是定义辅助方法的几行代码,但您可以在整个地方重用它作为一个衬里,而且它更具可读性,如果不是那么聪明的话。

【讨论】:

  • 感谢您的详尽回答!
  • 别担心/祝你好运。显然,Anu 的解决方案更适合纯三元方法(我尝试过但处于 PS 模式,所以使用 [ref] 而不是 ref 并得出结论它不起作用;doh!)。祝你好运。
【解决方案4】:

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

//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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多