C# 非常数开关的替代方案
我刚刚了解到switch语句不能使用非常量条件。这很好,我明白了。但这真的意味着我必须做一个大的if else块吗?太难看了,我都哭了 一些背景:我正在做一个Unity项目,我想打开当前的动画状态。检查当前动画状态的一个好方法是比较哈希值,这意味着我需要计算动画状态的哈希值。计算完之后,我想打开它们。(写这篇文章时,我意识到我可以将结果哈希粘贴到一个常量中,但现在我仍然需要一个答案)C# 非常数开关的替代方案,c#,switch-statement,C#,Switch Statement,我刚刚了解到switch语句不能使用非常量条件。这很好,我明白了。但这真的意味着我必须做一个大的if else块吗?太难看了,我都哭了 一些背景:我正在做一个Unity项目,我想打开当前的动画状态。检查当前动画状态的一个好方法是比较哈希值,这意味着我需要计算动画状态的哈希值。计算完之后,我想打开它们。(写这篇文章时,我意识到我可以将结果哈希粘贴到一个常量中,但现在我仍然需要一个答案) 执行此操作的最佳方法是什么?只有在以下情况下,才能使用if-else执行此操作: int state1 = An
执行此操作的最佳方法是什么?只有在以下情况下,才能使用if-else执行此操作:
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
if (hash == state1) {
//DoStuff
}
else if (hash == state2) {
//Other stuff
}
你能否简化它取决于你的“DoStuff”、“其他东西”、“下一个东西”和“你其他东西”之间的相似性
东西
“家庭成员”实际上是:
int stuffAction(int state){
int modified_state;
//do something on state and modified state
return modified_state;
}
然后,显然可以通过使用函数来简化工作
,如上所示。只要你的东西
具有相同的函数和不同的参数,它同样可以简化Stuff
采用不同的函数形式,但具有相同的输入参数,则可以创建代理的字典(请参见System.Collections.Generic.Dictionary
),以便在调用Stuff
时只需执行以下操作
dic[state](input parameters here)
而不是使用if-else或switch
可能会有一些代码无法进一步简化的可能性,但正如我前面所说的,底线是取决于您的
内容之间的相似性。您可以使用字典来实现这一点
试试这个:
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
var cases = new Dictionary<Func<bool>, Action>()
{
{ () => hash == state1, () => { /* Do stuff */} },
{ () => hash == state2, () => { /* Do other stuff */} },
};
cases
.Where(c => c.Key()) // find conditions that match
.Select(kvp => kvp.Value) //select the `Action`
.FirstOrDefault() // take only the first one
?.Invoke(); // Invoke the action only if not `null`
然后代码如下所示:
public class Switch : IEnumerable<Switch.Case>
{
private List<Case> _list = new List<Case>();
public void Add(Func<bool> condition, Action action)
{
_list.Add(new Case(condition, action));
}
IEnumerator<Case> IEnumerable<Case>.GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}
public void Execute()
{
this
.Where(c => c.Condition())
.Select(c => c.Action)
.FirstOrDefault()
?.Invoke();
}
public sealed class Case
{
private readonly Func<bool> _condition;
private readonly Action _action;
public Func<bool> Condition { get { return _condition; } }
public Action Action { get { return _action; } }
public Case(Func<bool> condition, Action action)
{
_condition = condition;
_action = action;
}
}
}
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
var @switch = new Switch()
{
{ () => hash == state1, () => { /* Do stuff */} },
{ () => hash == state2, () => { /* Do other stuff */} },
};
@switch.Execute();
如果你这样写的话,它看起来就像一个普通的switch
语句:
var @switch = new Switch()
{
{
() => hash == state1,
() =>
{
/* Do stuff */
}
},
{
() => hash == state2,
() =>
{
/* Do other stuff */
}
},
};
您的上下文中的哈希值是唯一的吗?看起来很危险。为什么不将您的状态定义为Enum
,或者干脆定义为int
。为什么要对州进行哈希运算?状态应该有很好的定义,特别是如果你正在为它编写一个switch语句的话。OP特别提到不希望有一个“大的if-else块”,这就是它的含义。就我个人而言,我不认为这是一个问题,我可能会这样做。
var @switch = new Switch()
{
{
() => hash == state1,
() =>
{
/* Do stuff */
}
},
{
() => hash == state2,
() =>
{
/* Do other stuff */
}
},
};