在 c# 类型上切换大小写[重复]

问题描述 投票:0回答:5

可能重复:
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# .net optimization switch-statement
5个回答
178
投票

更新 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/


61
投票

以下代码的工作原理或多或少就像人们期望的类型开关只查看实际类型(例如

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

27
投票

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

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

16
投票

这是一个保持真实的选项,我可以满足OP的要求,能够打开类型。如果你仔细观察的话,它看起来几乎就像是一个真正的 switch 语句。

调用代码如下所示:

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

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

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


10
投票

最简单的事情可能是使用动态,即定义简单的方法,如 Yuval Peled 的回答:

void Test(WebControl c)
{
...
}

void Test(ComboBox c)
{
...
}

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

dynamic dynObj = obj;
Test(dynObj);
© www.soinside.com 2019 - 2024. All rights reserved.