简体   繁体   English

C#切换类型

[英]C# switch with types

EDIT: This is now available in C# 7.0. 编辑: 现在可以在C#7.0中使用。


I have the following piece of code that checks a given PropertyInfo 's type . 我有以下代码检查给定的PropertyInfotype

PropertyInfo prop;

// init prop, etc...

if (typeof(String).IsAssignableFrom(prop.PropertyType)) {
    // ...
}
else if (typeof(Int32).IsAssignableFrom(prop.PropertyType)) {
    // ...
}
else if (typeof(DateTime).IsAssignableFrom(prop.PropertyType)) {
    // ...
}

Is there a way to use a switch statement in this scenario? 有没有办法在这种情况下使用switch语句? This is my current solution: 这是我目前的解决方案:

switch (prop.PropertyType.ToString()) {
    case "System.String":
        // ...
        break;
    case "System.Int32":
        // ...
        break;
    case "System.DateTime":
        // ...
        break;
    default:
        // ...
        break;
}

I don't think this is the best solution, because now I have to give the fully qualified String value of the given type . 我不认为这是最好的解决方案,因为现在我必须给出给定type的完全限定的String值。 Any tips? 有小费吗?

This is now available in C# 7.0. 现在可以在C#7.0中使用它。

This solution is for my original question; 这个解决方案适合我原来的问题; switch statements work on the value of the PropertyInfo and not its PropertyType : switch语句处理PropertyInfovalue而不是PropertyType

PropertyInfo prop;

// init prop, etc...

var value = prop.GetValue(null);

switch (value)
{
    case string s:
        // ...
        break;
    case int i:
        // ...
        break;
    case DateTime d:
        // ...
        break;
    default:
        // ...
        break;
}

Slightly more generic answer: 稍微更通用的答案:

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

Reference: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/ 参考: https//blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

I'll answer the question exactly as asked: There is no way. 我将完全按照要求回答这个问题:没有办法。

switch as of C# 6 only supports matching constants of certain types exactly. 从C#6 switch只支持精确匹配某些类型的常量。 You are not trying to match constants. 你不是试图匹配常数。 You are invoking the IsAssignableFrom method many times. 您多次调用IsAssignableFrom方法。

Note, that IsAssignableFrom is not identical to matching types exactly. 注意, IsAssignableFrom相同的精确匹配的类型。 Therefore, any solution based on equality comparisons or hash tables can't work. 因此,任何基于相等比较或哈希表的解决方案都无法工作。

I think the if ... else if solution that you have is totally fine. 我认为if ... else if你拥有的解决方案完全没问题。

There's no general way, but more often that not, those branches contain very similar code. 没有通用的方法,但更常见的是,这些分支包含非常相似的代码。 One pattern that almost always works for me is to use a dictionary; 几乎总是对我有用的一种模式是使用字典;

var myIndex = new Dictionary<Type, string> {
    { typeof(string), "some text" },    
    { typeof(int), "a whole number" },    
    { typeof(decimal), "a fraction" },    
};

string description;
if (myIndex.TryGetValue(prop.PropertyType, out description)) {
    Console.WriteLine("This type is " + description);
} else {
    // 'default'
}

使用你拥有的ToString方法,但不是文字值使用case typeof(string).Name(如果可能的话)现在没有vs在我面前。

First of all IsAssignableFrom is better then just string comparing in case of inherited types. 首先, IsAssignableFrom比继承类型的字符串比较更好。 For example typeof(TextReader).IsAssignableFrom(typeof(StreamReader)) will be true , because StreamReader inherited from TextReader , also work's for interfaces. 例如typeof(TextReader).IsAssignableFrom(typeof(StreamReader))将为true ,因为StreamReader继承自TextReader ,也适用于接口。

If you need only direct comparison, I can suggest create Dictionary<Type,Action<PropertyInfo>> , for example: 如果您只需要直接比较,我可以建议创建Dictionary<Type,Action<PropertyInfo>> ,例如:

var typeSelector = new Dictionary<Type, Action<PropertyInfo>>()
{
    {typeof(int), IntAction }
    {typeof(string), StringAction }
    {typeof(DateTime), DateTimeAction }
};

Then you can use it like this: 然后你可以像这样使用它:

Action<PropertyInfo> action;
if (typeSelector.TryGetValue(prop.PropertyType, out action))
    action(prop);
else 
    throw new InvalidDataException("Unsupported type");

Sure in this case you will have to create method for each type, or write code during creation of dictionary. 在这种情况下,您必须为每种类型创建方法,或在创建字典期间编写代码。

As shown in Mårten Wikström's answer: " How to use switch-case on a Type? " you can use Type.GetTypeCode as such: 如MårtenWikström的回答所示:“ 如何在Type上使用switch-case? ”你可以使用Type.GetTypeCode

switch (Type.GetTypeCode(type))
{
    case TypeCode.Int32:
       // It's an int
    break;

    case TypeCode.String:
       // It's a string
    break;

    // Other type code cases here...

    default:
        // Fallback to using if-else statements...
        if (type == typeof(MyCoolType))
        {
           // ...
        }
        else if (type == typeof(MyOtherType))
        {
           // ...
    } // etc...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM