c型开关箱

本文关键字:开关箱 | 更新日期: 2023-09-27 18:07:10

可能重复:
C#-对于';开关类型';?

你好,假设我收到了一个关于类类型的大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;
}

}

c型开关箱

更新C#7

是:来源

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

C#7之前

没有。

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/

以下代码的工作原理或多或少与只查看实际类型(例如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); }
}

是的,您可以打开名称。。。

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

这里有一个选项保持不变,我可以根据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;
}

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

尽管如此,它还是有效的。享受

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

void Test(WebControl c)
{
...
}
void Test(ComboBox c)
{
...
}

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

dynamic dynObj = obj;
Test(dynObj);