切换案例类型为c#

时间:2011-08-31 03:15:11

标签: c# .net optimization switch-statement

  

可能重复:
  C# - Is there a better alternative than this to 'switch on type'?

你好假设我在类类型上获得了一个很大的if / else。有没有办法用开关盒做到这一点?

示例:

function test(object obj)
{
if(obj is WebControl)
{

}else if(obj is TextBox)
{

}
else if(obj is ComboBox)
{

}
等等......

我想创建像

这样的东西
switch(obj)
{
case is TextBox:
break;
case is ComboBox:
break;

}

}

5 个答案:

答案 0 :(得分:59)

没有。

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

  

我们收到很多关于C#语言和今天的添加请求   我将谈谈一个比较常见的 - 开启类型。   开启类型看起来像一个非常有用和直接的功能:   添加一个类似开关的结构,它可以打开类型   表达式,而不是值。这可能看起来像   这样:

switch typeof(e) { 
        case int:    ... break; 
        case string: ... break; 
        case double: ... break; 
        default:     ... break; 
}
  

这种声明对于添加虚拟非常有用   方法,如在不相交的类型层次结构上调度,或在类型上调度   包含您不拥有的类型的层次结构。看到像这样的例子   这个,你可以很容易地得出这个特征的结论   简单而有用。它甚至可能让你想到“为什么不   那些#*&%$懒惰的C#语言设计师让我的生活更轻松   添加这个简单,省时的语言功能?“

     

不幸的是,像许多'简单'的语言功能一样,类型切换是   并不像它第一次出现那么简单。当你看时,麻烦就开始了   一个更重要,同样重要的例子:

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/

更新C#7

是:Source

switch(shape)
{
    case Circle c:
        WriteLine($"circle with radius {c.Radius}");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} square");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} rectangle");
        break;
    default:
        WriteLine("<unknown shape>");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}

答案 1 :(得分:50)

以下代码或多或少地起作用,因为人们期望只查看实际类型的类型开关(例如GetType()返回的内容)。

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"); 
}

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

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); }
}

答案 2 :(得分:22)

是的,你可以打开名字......

switch (obj.GetType().Name)
{
    case "TextBox":...
}

答案 3 :(得分:13)

这是一个保持真实的选项我可以满足OP要求能够打开类型。如果你足够眯眼,它几乎看起来像一个真正的开关声明。

调用代码如下所示:

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是强类型的。无需铸造。

为了完成这项神奇的工作,你需要这两种方法:

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;
}

几乎给你的眼睛带来了眼泪,对吗?

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

答案 4 :(得分:9)

最简单的方法是使用动力学,即你在Yuval Peled回答中定义简单的方法:

void Test(WebControl c)
{
...
}

void Test(ComboBox c)
{
...
}

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

dynamic dynObj = obj;
Test(dynObj);