关于.net:在c#类型上切换案例

Switch case on type c#

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
C# - Is there a better alternative than this to 'switch on type'?

你好,假设我有一个很大的if/else类。有办法用开关箱吗?

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
function test(object obj)
{
if(obj is WebControl)
{

}else if(obj is TextBox)
{

}
else if(obj is ComboBox)
{

}

等。。。

我想创造一些

1
2
3
4
5
6
7
8
switch(obj)
{
case is TextBox:
break;
case is ComboBox:
break;

}

}


不。

http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx网站

We get a lot of requests for addditions to the C# language and today
I'm going to talk about one of the more common ones - switch on type.
Switch on type looks like a pretty useful and straightforward feature:
Add a switch-like construct which switches on the type of the
expression, rather than the value. This might look something like
this:

1
2
3
4
5
6
switch typeof(e) {
        case int:    ... break;
        case string: ... break;
        case double: ... break;
        default:     ... break;
}

This kind of statement would be extremely useful for adding virtual
method like dispatch over a disjoint type hierarchy, or over a type
hierarchy containing types that you don't own. Seeing an example like
this, you could easily conclude that the feature would be
straightforward and useful. It might even get you thinking"Why don't
those #*&%$ lazy C# language designers just make my life easier and
add this simple, timesaving language feature?"

Unfortunately, like many 'simple' language features, type switch is
not as simple as it first appears. The troubles start when you look at
a more significant, and no less important, example like this:

1
2
3
4
5
6
7
8
9
class C {}
interface I {}
class D : C, I {}

switch typeof(e) {
case C:break;
case I:break;
default:break;
}

链接:https://blogs.msdn.microsoft.com/peterhal/2005/07/05/many-questions-switch-on-type/


下面的代码或多或少地工作,正如人们所期望的那样,类型开关只查看实际的类型(例如,GetType()返回的类型)。

1
2
3
4
5
6
7
8
9
10
11
public static void TestTypeSwitch()
{
    var ts = new TypeSwitch()
        .Case((int x) => Console.WriteLine("int"))
        .Case((bool x) => Console.WriteLine("bool"))
        .Case((string x) => Console.WriteLine("string"));

    ts.Switch(42);    
    ts.Switch(false);  
    ts.Switch("hello");
}

这是使它工作所需的机器。

1
2
3
4
5
6
public class TypeSwitch
{
    Dictionary<Type, Action<object>> matches = new Dictionary<Type, Action<object>>();
    public TypeSwitch Case<T>(Action<T> action) { matches.Add(typeof(T), (x) => action((T)x)); return this; }
    public void Switch(object x) { matches[x.GetType()](x); }
}


是的,您可以打开名称…

1
2
3
4
switch (obj.GetType().Name)
{
    case"TextBox":...
}


这里有一个选择,保持不变,我可以使它的OP的要求,能够打开类型。如果你眯起眼睛,它看起来就像一个真正的switch语句。

呼叫代码如下:

1
2
3
4
5
6
7
8
var @switch = this.Switch(new []
{
    this.Case<WebControl>(x => { /* WebControl code here */ }),
    this.Case<TextBox>(x => { /* TextBox code here */ }),
    this.Case<ComboBox>(x => { /* ComboBox code here */ }),
});

@switch(obj);

上面每个lambda中的x是强类型的。无需铸造。

要使这个魔法发挥作用,你需要以下两种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private Action<object> Switch(params Func<object, Action>[] tests)
{
    return o =>
    {
        var @case = tests
            .Select(f => f(o))
            .FirstOrDefault(a => a != null);

        if (@case != null)
        {
            @case();
        }
    };
}

private Func<object, Action> Case<T>(Action<T> action)
{
    return o => o is T ? (Action)(() => action((T)o)) : (Action)null;
}

几乎让你热泪盈眶,对吧?

尽管如此,它仍然有效。享受。


要做的最简单的事情可能是使用动力学,也就是说,您定义了类似于yuval-peled答案中的简单方法:

1
2
3
4
5
6
7
8
9
void Test(WebControl c)
{
...
}

void Test(ComboBox c)
{
...
}

然后不能直接调用test(obj),因为重载解析是在编译时完成的。您必须将对象分配给一个动态对象,然后调用测试方法:

1
2
dynamic dynObj = obj;
Test(dynObj);