C# - 如果在默认情况下,获取开关值

问题描述 投票:11回答:4

请大家帮忙,我有这个案例。

switch(MyFoo()){
    case 0: //...
        break;
    case 1: //...
        break;
    case 2: //...
        break;
    default:
        // <HERE>
        break;
}

如你所见,开关直接从一个方法中获取值,而没有将其保存为一个变量。

是否可以得到哪个值触发了 default 的情况下?例如如果 MyFoo() 返回7,怎样才能得到这个值?

我想避免把方法的结果保存为一个变量,有没有办法从case里面获取开关值?类似这样的。

default:
    this.SwitchValue // <<--
    break;

谢谢你的阅读,~Saba

c# switch-statement
4个回答
14
投票

有什么方法可以从case里面获取开关值吗?

唯一(正确)的方法实际上是将结果存储在 MyFoo() 在一个变量中。

var fooResult = MyFoo();
switch (fooResult)
{
    case 0:
        ...
        break;
    ...
    default:
        handleOthersCase(fooResult);
        break;
}

这段代码是可读可懂的,而且没有额外的成本(正如@SheldonNeilson所说:反正它在栈上)。

另外,MSDN的第一个例子是关于 开关 完全是这个样子。你也可以找到信息在 语言规范.

你也可以自己做 开关 基于 词典但我看到的唯一优势是,你可以用它来处理复杂的 案件 任何一种对象而不是stringint...)。性能是一个缺点。

它可能看起来像这样。

public class MySwitch<T> : Dictionary<T, Action<T>>
{
    private Action<T> _defaultAction;

    public void TryInvoke(T value)
    {
        Action<T> action;
        if (TryGetValue(value, out action))
        {
            action(value);
        }
        else
        {
            var defaultAction = _defaultAction;
            if (defaultAction != null)
            {
                defaultAction(value);
            }
        }
    }

    public void SetDefault(Action<T> defaultAction)
    {
        _defaultAction = defaultAction;
    }
}

然后像这样使用:

var mySwitch = new MySwitch<int>();

mySwitch.Add(1, i => Console.WriteLine("one"));                             // print "one"
mySwitch.Add(2, i => Console.WriteLine("two"));                             // print "two"
mySwitch.SetDefault(i => Console.WriteLine("With the digits: {0}", i));     // print any other value with digits.

mySwitch.TryInvoke(42);                                                     // Output: "With the digits: 42"

或者基于 此回答,这个。

public class MySwitch2<T>
{
    private readonly T _input;

    private bool _done = false;

    private MySwitch2(T input)
    {
        _input = input;
    }

    public MySwitch2<T> On(T input)
    {
        return new MySwitch2<T>(input);
    }

    public MySwitch2<T> Case(T caseValue, Action<T> action)
    {
        if (!_done && Equals(_input, caseValue))
        {
            _done = true;
            action(_input);
        }
        return this;
    }

    public void Default(Action<T> action)
    {
        if (!_done)
        {
            action(_input);
        }
    }
}

可以这样使用。

MySwitch2<int>.On(42)
    .Case(1, i => Console.WriteLine("one"))
    .Case(2, i => Console.WriteLine("two"))
    .Default(i => Console.WriteLine("With the digits: {0}", i));

5
投票

我也不知道为什么要这么用,但可能有一个变通的办法就是这样。

int x;
switch ( x = MyFoo())
{
    case 0: //...
        break;
    case 1: //...
        break;
    case 2: //...
        break;
    default:
        var s = x; // Access and play with x here
        break;
}

3
投票

不,这是不可能的,你可以把值赋给开关里面的变量,如果你想看起来像重新发明轮子的话。

        int b;
        .....
        switch (b = MyFoo())
        {
            case 1:
                break;
            case 2:
                break;
            default:
                //do smth with b
                break;
        }

1
投票

最简单的方法是把结果保存在... MyFoo() 作为一个变量。但如果你不想这样做,你可以这样做。

switch(MyFoo()){
    case 0: //...
        break;
    case 1: //...
        break;
    case 2: //...
        break;
    default:
        this.SwitchCase = MyFoo();
        break;
}

不过我建议你不要这样做 把值保存为一个变量 以节省你的程序的额外工作。

保存变量的值 MyFoo 作为一个变量,这个例子变得越复杂越重要,因为 MyFoo 可以在切换和默认情况下改变。

另外,这只适用于 MyFoo 没有任何副作用,而且对于任何给定的参数,显然必须总是返回相同的值。

例如,下面的代码可以用。

Private int MyFoo()
{
   return 3;
}

但下面就不行了

private int MyFoo()
{
  Random r = new Random();
  return r.Next(5);
}
© www.soinside.com 2019 - 2024. All rights reserved.