问题
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. Performinga = c
assigns the value ofc
toa
, but doesn't return anything to the caller.(a = c)
on the other hand assignsc
toa
and then outputs the new value ofa
, 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