2015-12-17 14 views
7

EDIT: This is now available in C# 7.0.C# chuyển đổi với các loại


Tôi có đoạn mã sau đây để kiểm tra một cho 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)) { 
    // ... 
} 

Có cách nào để sử dụng câu lệnh switch trong trường hợp này không? Đây là giải pháp hiện tại của tôi:

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

Tôi không nghĩ rằng đây là giải pháp tốt nhất, bởi vì bây giờ tôi phải cung cấp cho các giá trị String đầy đủ của type nhất định. Có lời khuyên nào không?

+0

tôi nghĩ rằng không có cách nào. Chuyển đổi hoạt động chủ yếu trên chuỗi, int và enum (int một lần nữa bheind hiện trường). Với được gán từ bạn có thể kiểm tra ngay cả loại thừa hưởng hình thức khác, với chuỗi này là definetly impossibile. – Skary

+0

nếu các loại bạn đang làm việc chỉ là Int32, chuỗi và DateTime, nếu bạn có thể sử dụng == thay vì IsAssignableFrom (chúng được niêm phong lớp): nếu (prop.PropertyType == typeof (string) ... , bạn không thể sử dụng typeof (someClass) làm nhãn trường hợp, bạn cũng không thể sử dụng đối số Nhập làm đối số chuyển đổi Tôi sẽ ở lại nếu –

+0

Có thể trùng lặp của [Có cách nào tốt hơn thay thế này để 'bật kiểu' không? ] (http://stackoverflow.com/questions/298976/is-there-a-better-alternative-than-this-to-switch-on-type) – Dmitry

Trả lời

4

Tôi sẽ trả lời câu hỏi chính xác như được hỏi: Không có cách nào.

switch vì C# 6 chỉ hỗ trợ chính xác các hằng số của một số loại nhất định. Bạn không cố gắng để phù hợp với hằng số. Bạn đang gọi phương thức IsAssignableFrom nhiều lần.

Lưu ý rằng IsAssignableFromkhông phải giống hệt với loại đối sánh chính xác. Vì vậy, bất kỳ giải pháp dựa trên so sánh bình đẳng hoặc bảng băm không thể làm việc.

Tôi nghĩ giải pháp if ... else if mà bạn có là hoàn toàn ổn.

3

Không có cách tổng quát, nhưng thường thì không, các nhánh đó chứa mã rất giống nhau. Một mẫu mà hầu như luôn hoạt động đối với tôi là sử dụng từ điển;

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

Sử dụng phương pháp ToString bạn có, nhưng thay vì giá trị bằng chữ, hãy sử dụng kiểu chữ (chuỗi) .Name (nếu có thể) không có so với trước tôi ngay bây giờ.

1

Trước hết, IsAssignableFrom tốt hơn là chỉ so sánh chuỗi trong trường hợp loại được kế thừa. Ví dụ: typeof(TextReader).IsAssignableFrom(typeof(StreamReader)) sẽ là true, vì StreamReader được kế thừa từ TextReader, cũng hoạt động cho giao diện.

Nếu bạn chỉ cần so sánh trực tiếp, tôi có thể đề nghị tạo Dictionary<Type,Action<PropertyInfo>>, ví dụ:

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

Sau đó, bạn có thể sử dụng nó như thế này:

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

Chắc chắn trong trường hợp này bạn sẽ phải tạo phương thức cho từng loại hoặc viết mã trong khi tạo từ điển.

6

Tính năng này hiện khả dụng trong C# 7.0.

Giải pháp này dành cho câu hỏi ban đầu của tôi; switch báo cáo hoạt động trên value của PropertyInfo và không PropertyType của nó:

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

câu trả lời Hơi chung chung hơn:

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

tham khảo: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

+0

I "Phương thức không tĩnh đòi hỏi một đích" khi cố gắng 'prop.GetValue (null)'. –

+0

Hmm, và nếu tôi làm 'prop.GetValue (model)' (với một lớp instantiated mà tôi đang làm việc với), kết hợp mẫu có vẻ chỉ hoạt động với bool, và nếu không thì nhấn vào trường hợp mặc định. –

+1

@TannerFaulkner Bạn có thể cung cấp .NET Fiddle không? –

0

Như đã trình bày trong câu trả lời Marten Wikström của: "How to use switch-case on a Type?" bạn có thể sử dụng Type.GetTypeCode như vậy:

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... 
} 
Các vấn đề liên quan