My app will involve a lot of modifying of static fields. I'm wondering how to update the static fields from different classes by passing them as a method argument to a utility setter method.
internal static class Hero1
{
public static bool awesomeAbility = false;
public static bool anotherAwesomeAbility = false;
}
internal static class Hero2
{
public static bool awesomeAbility = false;
public static bool anotherAwesomeAbility = false;
}
internal static class Utils
{
public static async void ToggleAbility(ability, bool value)
{
Logger.Write($@"{ability} = {value}");
ability = value;
}
}
// example usage....
ToggleAbility(Hero1.awesomeAbility, true);
ToggleAbility(Hero2.anotherAwesomeAbility, false);
It is possible to do this if you allow the caller to pass an expression tree (Expression<Func<bool>>
), then you can get the field referenced by the expression tree as a FieldInfo
.
async void ToggleAbility(Expression<Func<bool>> field, bool value) {
if (field.Body is MemberExpression memberExpression &&
memberExpression.Member is FieldInfo fieldInfo) {
// instead of field.Body, you can also use fieldInfo.Name for a simple name
Logger.Write($@"{field.Body} = {fieldInfo.GetValue(null)}");
// this sets the field's value
fieldInfo.SetValue(null, value);
// if you want to set it back asynchronously some time later...
// await Task.Delay(...);
// fieldInfo.SetValue(null, !value);
} else {
// the expression tree is not an access to a public static field
// you could e.g. throw an exception
}
}
Usage:
ToggleAbility(() => Hero1.awesomeAbility, true);
Setting a field with SetValue
is not very fast. If that is a problem for you, you can take a "field setter" Action<bool>
async void ToggleAbility(Action<bool> setter, bool value) {
setter(value)
await Task.Delay(...);
setter(!vakue)
}
ToggleAbility(x => Hero1.awesomeAbility = x, true);
However, you cannot access the field name or its current value in ToggleAbility
with this approach, unless you also pass them in as additional parameters:
ToggleAbility(
x => Hero1.awesomeAbility = x,
true,
nameof(Hero1.awesomeAbility),
Hero1.awesomeAbility);
If your method doesn't need to be async, you can also pass the field in as a ref
parameter, as lidqy's answer shows.