Truyền vào Enum Chung trong C #


84

Tương tự như Cast int to enum trong C # nhưng enum của tôi là một tham số Generic Type. Là gì tốt nhất cách để xử lý này?

Thí dụ:

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

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

Mã đầy đủ như sau, trong đó giá trị có thể chứa 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;
}

stackoverflow.com/questions/2745320/… - có thể giúp được gì không?
Nắng

Câu trả lời cuối cùng trên stackoverflow.com/questions/1331739/… , gần với những gì bạn muốn hơn. Nó vẫn không thông minh mặc dù. 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. Theo ý kiến ​​của tôi, Struct không đủ bắt buộc để làm cho việc xáo trộn với các generic trở nên đáng giá.
Tony Hopkinson

1
Một cái gì đó mà không hộp: c-sharp-phi-boxing chuyển đổi-of-generic-enum-to-int
nawfal

Câu trả lời:


120

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

return (T)(object)i.Value;

12
Nếu bạn không thích quyền anh: c-sharp-non-boxing-convert-of-generic-enum-to-int
nawfal

5
Chúng ta đang ép kiểu enum thành int, không phải ngược lại như trong câu hỏi So you link. Ngoài ra, câu hỏi đó không có lời giải.
MatteoSp

Bạn cũng có thể chỉ cần cấp phát 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 để truy xuất enum chính xác. Điều này giúp tiết kiệm phải thực hiện bất kỳ loại truyền nào. Ví dụ (Chỉ dòng 11,14, và 34 có liên quan đến khái niệm này): pastebin.com/iPEzttM4
Krythic

20

Bạn sẽ có thể sử dụng Enum.Parsecho 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 cú pháp các enum chung cho các phương thức mở rộng:


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

16

Đây là một giải pháp rất nhanh lạm dụng thực tế là thời gian chạy tạo ra nhiều trường hợp của các lớp chung tĩnh. Giải phóng những con 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ừ một luồng theo kiểu chung chung. Kết hợp với một lớp bên ngoài cũng lưu trữ loại cơ bản của enum và một BitConverter để giải phóng điều 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 bậ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

2
Điều này thực sự tốt đẹp, cảm ơn. Tuy nhiên, bạn có thể muốn sử dụng Expression.ConvertCheckedthay thế, vì vậy việc tràn số của phạm vi kiểu enum dẫn đến OverflowException.
Drew Noakes

Số dặm của bạn có thể thay đổi, tôi đã chạy mã trên try.dot.net (blazor) và ở đó EnumConverter <T> chậm hơn nhiều so với các lựa chọn thay thế. Truyền tới đối tượng đầu tiên chậm hơn khoảng 6 lần so với truyền trực tiếp, nhưng vẫn tốt hơn nhiều so với các tùy chọn khác.
Herman



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);
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.