2012-04-30 37 views
50

Tương tự như Cast int to enum in C# nhưng enum của tôi là một tham số Kiểu chung. Phương pháp tốt nhất để xử lý điều này là gì?Cast Int to Generic Enum trong C#

Ví dụ:

private T ConvertEnum<T>(int i) where T : struct, IConvertible 
{ 
    return (T)i; 
} 

Tạo biên dịch lỗi Cannot convert type 'int' to 'T'

Full mã như sau, trong đó giá trị có thể chứa các int, hoặc null.

private int? TryParseInt(string value) 
{ 
    var i = 0; 
    if (!int.TryParse(value, out i)) 
    { 
     return null; 
    } 
    return i; 
} 

private T? TryParseEnum<T>(string value) where T : struct, IConvertible 
{ 
    var i = TryParseInt(value); 
    if (!i.HasValue) 
    { 
     return null; 
    } 

    return (T)i.Value; 
} 
+0

http://stackoverflow.com/questions/2745320/enum-tryparse-with-flags-attribute - có thể giúp ? – Sunny

+0

Câu trả lời cuối cùng trên http://stackoverflow.com/questions/1331739/enum-type-constraints-in-c-sharp, gần hơn với những gì bạn muốn. Nó vẫn không thông minh. Tôi có xu hướng sử dụng sự phản chiếu cho điều này, bạn có thể làm cho mã mạnh hơn rất nhiều. Struct không đủ để làm cho rối tung với các generics đáng giá theo ý kiến ​​của tôi. –

+0

Nội dung không có trong hộp: [c-sharp-không-boxing-chuyển đổi-of-generic-enum-to-int] (http://stackoverflow.com/questions/1189144/c-sharp-non-boxing- conversion-of-generic-enum-to-int) – nawfal

Trả lời

76

Cách đơn giản nhất tôi tìm thấy là bắt tay của trình biên dịch bằng cách thêm dàn diễn viên vào object.

return (T)(object)i.Value; 
+10

Nếu bạn không thích boxing: [c-sharp-non-boxing-conversion-of-generic-enum-to-int] (http://stackoverflow.com)/câu hỏi/1189144/c-sharp-không-boxing-chuyển đổi-of-generic-enum-to-int) – nawfal

+2

Chúng tôi đang đúc enum để int, không phải là trái như trong câu hỏi bạn liên kết. Ngoài ra, câu hỏi đó không có giải pháp. – MatteoSp

+0

Bạn cũng có thể chỉ phân bổ một mảng tĩnh với các giá trị enum, và sau đó chỉ cần chuyển vào chỉ mục để lấy đúng enum. Điều này tiết kiệm phải làm bất kỳ loại đúc. Ví dụ (Chỉ dòng 11,14 và 34 có liên quan đến khái niệm này): https://pastebin.com/iPEzttM4 – Krythic

11

Bạn sẽ có thể sử dụng Enum.Parse cho việc này:

return (T)Enum.Parse(typeof(T), i.Value.ToString(), true); 

Bài viết này nói về phân tích sự đếm chung cho phương pháp extenstion:

+0

@Guvante: Tôi nghĩ rằng tôi đã chuyển đổi giá trị thành chuỗi trong ví dụ của tôi. Bạn có thấy trước điều này gây ra sự cố không? –

14

Dưới đây là một giải pháp rất nhanh chóng lạm dụng thực tế rằng thời gian chạy tạo ra nhiều phiên bản của các lớp chung chung tĩnh. Giải phóng ma quỷ tối ưu hóa bên trong của bạn!

Điều này thực sự tỏa sáng khi bạn đang đọc Enums từ luồng theo kiểu chung. Kết hợp với một lớp bên ngoài cũng lưu trữ kiểu cơ bản của enum và một BitConverter để giải phóng tuyệt vời.

void Main() 
{ 
    Console.WriteLine("Cast (reference): {0}", (TestEnum)5); 
    Console.WriteLine("EnumConverter: {0}", EnumConverter<TestEnum>.Convert(5)); 
    Console.WriteLine("Enum.ToObject: {0}", Enum.ToObject(typeof(TestEnum), 5)); 

    int iterations = 1000 * 1000 * 100; 
    Measure(iterations, "Cast (reference)",() => { var t = (TestEnum)5; }); 
    Measure(iterations, "EnumConverter",() => EnumConverter<TestEnum>.Convert(5)); 
    Measure(iterations, "Enum.ToObject",() => Enum.ToObject(typeof(TestEnum), 5)); 
} 

static class EnumConverter<TEnum> where TEnum : struct, IConvertible 
{ 
    public static readonly Func<long, TEnum> Convert = GenerateConverter(); 

    static Func<long, TEnum> GenerateConverter() 
    { 
     var parameter = Expression.Parameter(typeof(long)); 
     var dynamicMethod = Expression.Lambda<Func<long, TEnum>>(
      Expression.Convert(parameter, typeof(TEnum)), 
      parameter); 
     return dynamicMethod.Compile(); 
    } 
} 

enum TestEnum 
{ 
    Value = 5 
} 

static void Measure(int repetitions, string what, Action action) 
{ 
    action(); 

    var total = Stopwatch.StartNew(); 
    for (int i = 0; i < repetitions; i++) 
    { 
     action(); 
    } 
    Console.WriteLine("{0}: {1}", what, total.Elapsed); 
} 

Kết quả trên Core i7-3740QM với tối ưu hóa được kích hoạt:

Cast (reference): Value 
EnumConverter: Value 
Enum.ToObject: Value 
Cast (reference): 00:00:00.3175615 
EnumConverter: 00:00:00.4335949 
Enum.ToObject: 00:00:14.3396366 
+0

Điều này thực sự tốt đẹp, cảm ơn. Thay vào đó, bạn có thể sử dụng 'Expression.ConvertChecked', do đó, tràn số của phạm vi loại enum sẽ dẫn đến một' OverflowException'. –

0
public static class Extensions 
    { 
     public static T ToEnum<T>(this int param) 
     { 
      var info = typeof(T); 
      if (info.IsEnum) 
      { 
       T result = (T)Enum.Parse(typeof(T), param.ToString(), true); 
       return result; 
      } 

      return default(T); 
     } 
    }