2015-12-17 14 views
7

EDIT: This is now available in C# 7.0.C# przełącznik z typów


Mam następujący fragment kodu, który sprawdza dany PropertyInfo „s type.

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)) { 
    // ... 
} 

Czy istnieje sposób, aby użyć switch oświadczenie w tym scenariuszu? To jest mój obecny rozwiązanie:

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

Nie sądzę, jest to najlepsze rozwiązanie, bo teraz muszę dać pełną String wartość danego type. Jakieś wskazówki?

+0

myślę, nie ma sposobu. Przełącznik działa głównie na stringach, int i enum (int ponownie zmienia scenę). Z można przypisać z można sprawdzić nawet typ, który dziedziczy z innego, z ciągiem jest to zdecydowanie niemożliwe. – Skary

+0

Jeśli Typy, z którymi pracujesz, to tylko Int32, string i DateTime, twoje jeśli mogą użyć == zamiast IsAssignableFrom (są klasami zapieczętowanymi): if (prop.PropertyType == typeof (string) ... Ale mimo to , nie możesz użyć typeof (someClass) jako etykiety case, ani nie możesz użyć argumentu Type jako przełącznika Pozostałbym z if Jeśli –

+0

Możliwy duplikat [Czy istnieje lepsza alternatywa niż ta, aby "włączyć typ"? ] (http://stackoverflow.com/questions/298976/is-there-a-better-alternative-than-this-to-switch-on-type) – Dmitry

Odpowiedz

4

Odpowiem dokładnie na pytanie: Nie ma mowy.

switch od C# 6 dokładnie obsługuje stałe stałe określonych typów. Nie próbujesz dopasować stałych. Wywołujesz wielokrotnie metodę IsAssignableFrom.

Pamiętaj, że IsAssignableFrom to , a nie identycznie jak w przypadku pasujących typów. Dlatego każde rozwiązanie oparte na porównaniach równości lub tabelach mieszających nie może działać.

Myślę, że rozwiązanie if ... else if, które masz, jest całkowicie w porządku.

3

Nie ma ogólnej drogi, ale częściej nie, te gałęzie zawierają bardzo podobny kod. Jeden wzór, który prawie zawsze działa dla mnie, to użycie słownika;

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' 
} 
1

Użyj metody ToString, ale zamiast literałów użyj caseof (string) .Name (jeśli to możliwe) nie masz teraz naprzeciwko mnie.

1

Przede wszystkim IsAssignableFrom jest lepszy niż porównanie ciągów w przypadku dziedziczonych typów. Na przykład typeof(TextReader).IsAssignableFrom(typeof(StreamReader)) będzie true, ponieważ StreamReader odziedziczona po TextReader, również praca dla interfejsów.

Jeśli trzeba tylko bezpośrednie porównanie, mogę zaproponować stworzenie Dictionary<Type,Action<PropertyInfo>>, na przykład:

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

Wtedy można go używać tak:

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

Sure w tym przypadku trzeba będzie utwórz metodę dla każdego typu lub wpisz kod podczas tworzenia słownika.

6

To jest teraz dostępne w języku C# 7.0.

To rozwiązanie jest dla mojego oryginalnego pytania; switch oświadczenia pracować na value z PropertyInfo a nie jego 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; 
} 

odpowiedź Nieco bardziej ogólna:

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

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

+0

I "Metoda niestatyczna wymaga celu" podczas próby 'prop.GetValue (null)'. –

+0

Hmm, i jeśli zrobię 'prop.GetValue (model)' (z instancjonowaną klasą, z którą pracuję) dopasowanie wzorca wydaje się działać tylko z boolem, i inaczej trafi w domyślny przypadek. –

+1

@TannerFaulkner Czy możesz podać .NET Fiddle? –

0

Jak pokazano w odpowiedzi Marten WIKSTRÖM za: „How to use switch-case on a Type?” można użyć Type.GetTypeCode jako takie:

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