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

假装没事ソ 提交于 2021-01-27 02:34:10

问题


is it possible to differ the variable I'm assigning to depending on a condition? The issue I came across is wanting to do this:

(bEquipAsSecondary ? currentWeaponOffhand : currentWeaponMainhand) = weaponToSwitchTo;

Instead of

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

Which results in the following error

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

So I was wondering if there was a way to do this to cut down on space used and - in my opinion - make it look a bit neater?


回答1:


To use terinary operator for picking the variable to assign value to, you could make use of ref locals/returns.For example,

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

Sample Output and Code

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

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

Output

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



回答2:


Not sure if a ternary operator is a better choice than a regular if-else statement here. But you can use Action, something like this:

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



回答3:


The best / closest to what you're after that I could think of is this:

_ = condition ? (a = c) : (b = c);

In context:

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}");

Outputs

a = 3; b = 2; c = 3

Explanation

  • _ = is required as the ternary operator is only available if we're assigning to something. Here we use _ as the "discard" variable; i.e. we don't care about the returned value; only that the operation itself occurs.

  • use of brackets (e.g. (a = c) is required around the assignment since we need to return a result. Performing a = c assigns the value of c to a, but doesn't return anything to the caller. (a = c) on the other hand assigns c to a and then outputs the new value of a, making it available in the context of the rest of the method. i.e. Aisde from the assignments this statement effectively reads _ = condition ? c : c;.

    • All else is as you'd expect from the standard ternary operator. However, any questions, please say.

Thoughts

It's not ideal as you have to specify each assignment separately; but does give you a form of shorthand...

I suspect this would generally be frowned upon in a code review though, since it's less readable than the standard if/else approach...


NB: In some other languages, a trick that could be used would be to have the condition act as an index for an array (e.g. false=0, true=1) and then exploit this in assigning the value... However, whilst you can force this in C#, it's not pretty:

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();
    }
}

That said, the above is talking about creating a more generic approach... If your use case is limited to weapon assignment / similar use cases, you could use a similar trick, such as this:

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{ /* ... */ }

If you find you're having to do a lot of statements like this throughout your code and want a way to keep your line count down, you're best of with something like this:

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;
        }
    }
}

i.e. Whilst this is several lines of code to define the helper method, you can reuse it all over the place as a one liner, and it's much more readable, if not so clever.




回答4:


You can use the ternary operator to choose an action that will update the right slot.

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


来源:https://stackoverflow.com/questions/53362087/is-there-a-way-to-use-a-ternary-operator-or-similar-method-for-picking-the-v

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!