问题
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 = cassigns the value ofctoa, but doesn't return anything to the caller.(a = c)on the other hand assignsctoaand 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