非常量开关的替代方案
Alternative to switch with non-constant
我刚了解到 switch 语句不能使用非常量条件。这很好,我明白了。但这真的意味着我必须做一个很大的 if-else 块吗?丑到哭了
一些上下文:我正在做一个 Unity 项目,我想打开当前的动画状态。检查当前动画状态的一个好方法是比较哈希值,这意味着我需要计算动画状态的哈希值。计算完它们后,我想打开它们。 (写这个我意识到我可以将结果哈希粘贴到一个常量中,但现在我仍然想要一个答案)
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
switch (hash):
{
case state1:
//DoStuff
break;
case state2:
//Other stuff
break;
}
最好的方法是什么?
你只能用 if-else if:
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"、"Other Stuff"、"Next Stuff"、"You other stuffs"
的相似度
假设您的 Stuff
"family members" 实际上是:
int stuffAction(int state){
int modified_state;
//do something on state and modified state
return modified_state;
}
那么,显然你Stuffs
可以通过使用函数来简化,就像上面显示的那样。只要您的 Stuff
具有相同的功能但参数不同,它也可以同样简化。
此外,如果您 Stuffs
具有不同的函数形式但具有相同的输入参数,您可以创建 Dictionary
of delegates
(请参阅 System.Collections.Generic.Dictionary<string, System.Delegate>
) 这样当你可以调用 Stuff
时你只需要做
dic[state](input parameters here)
而不是使用 if-else 或 switch
在某些情况下,您的代码可能无法进一步简化,但底线是,正如我之前所说,取决于您的 Stuff
之间的相似性。
你可以用字典来做到这一点。
试试这个:
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`
为了让它更干净一点,你可以这样定义 Switch
class:
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 */
}
},
};
您也可以这样使用case guards and local functions:
bool HashMatches(int TargetHash) => hash == TargetHash;
switch (true):
{
case true when HashMatches(state1):
//DoStuff
break;
case true when HashMatches(state2):
//Other stuff
break;
}
我刚了解到 switch 语句不能使用非常量条件。这很好,我明白了。但这真的意味着我必须做一个很大的 if-else 块吗?丑到哭了
一些上下文:我正在做一个 Unity 项目,我想打开当前的动画状态。检查当前动画状态的一个好方法是比较哈希值,这意味着我需要计算动画状态的哈希值。计算完它们后,我想打开它们。 (写这个我意识到我可以将结果哈希粘贴到一个常量中,但现在我仍然想要一个答案)
int state1 = Animator.StringToHash("State1");
int state2 = Animator.StringToHash("State2");
int hash = _myAnimator.GetCurrentAnimatorStateInfo(0).shortNameHash;
switch (hash):
{
case state1:
//DoStuff
break;
case state2:
//Other stuff
break;
}
最好的方法是什么?
你只能用 if-else if:
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"、"Other Stuff"、"Next Stuff"、"You other stuffs"
的相似度假设您的
Stuff
"family members" 实际上是:int stuffAction(int state){ int modified_state; //do something on state and modified state return modified_state; }
那么,显然你
Stuffs
可以通过使用函数来简化,就像上面显示的那样。只要您的Stuff
具有相同的功能但参数不同,它也可以同样简化。此外,如果您
Stuffs
具有不同的函数形式但具有相同的输入参数,您可以创建Dictionary
ofdelegates
(请参阅System.Collections.Generic.Dictionary<string, System.Delegate>
) 这样当你可以调用Stuff
时你只需要做dic[state](input parameters here)
而不是使用 if-else 或 switch
在某些情况下,您的代码可能无法进一步简化,但底线是,正如我之前所说,取决于您的 Stuff
之间的相似性。
你可以用字典来做到这一点。
试试这个:
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`
为了让它更干净一点,你可以这样定义 Switch
class:
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 */
}
},
};
您也可以这样使用case guards and local functions:
bool HashMatches(int TargetHash) => hash == TargetHash;
switch (true):
{
case true when HashMatches(state1):
//DoStuff
break;
case true when HashMatches(state2):
//Other stuff
break;
}