C# 非常数开关的替代方案

C# 非常数开关的替代方案,c#,switch-statement,C#,Switch Statement,我刚刚了解到switch语句不能使用非常量条件。这很好,我明白了。但这真的意味着我必须做一个大的if else块吗?太难看了,我都哭了 一些背景:我正在做一个Unity项目,我想打开当前的动画状态。检查当前动画状态的一个好方法是比较哈希值,这意味着我需要计算动画状态的哈希值。计算完之后,我想打开它们。(写这篇文章时,我意识到我可以将结果哈希粘贴到一个常量中,但现在我仍然需要一个答案) 执行此操作的最佳方法是什么?只有在以下情况下,才能使用if-else执行此操作: int state1 = An

我刚刚了解到switch语句不能使用非常量条件。这很好,我明白了。但这真的意味着我必须做一个大的if else块吗?太难看了,我都哭了

一些背景:我正在做一个Unity项目,我想打开当前的动画状态。检查当前动画状态的一个好方法是比较哈希值,这意味着我需要计算动画状态的哈希值。计算完之后,我想打开它们。(写这篇文章时,我意识到我可以将结果哈希粘贴到一个常量中,但现在我仍然需要一个答案)


执行此操作的最佳方法是什么?

只有在以下情况下,才能使用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 */
            }
        },
    };