C# 为什么这个泛型方法调用不能编译?

C# 为什么这个泛型方法调用不能编译?,c#,generics,enums,C#,Generics,Enums,I一个扩展较短的枚举: public enum EnumType : short { Value1 = 1, Value2 = 2 } 然后我有一个实用方法,看起来像这样: public static class EnumUtilities { public static IEnumerable<Tuple<TEnum, TBase>> GetTuples<TEnum, TBase>() where TEnum : s

I一个扩展较短的枚举:

public enum EnumType : short
{
    Value1 = 1,
    Value2 = 2
}
然后我有一个实用方法,看起来像这样:

public static class EnumUtilities
{
    public static IEnumerable<Tuple<TEnum, TBase>> GetTuples<TEnum, TBase>()
        where TEnum : struct, TBase
    {
        return GetValues<TEnum>().Select(x => new Tuple<TEnum, TBase>(x, x));
    }

    public static IEnumerable<T> GetValues<T>() where T : struct
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }
}

问题的原因是在您编写的GetTuplesgeneric方法约束中

TEnum: struct, TBase
这意味着TEnum应该是从TBase派生的类型。我想您尝试过这样称呼它:EnumUtilities.GetTuples。问题是,EnumType不是从short派生的

你宣布的方式:

public enum EnumType: short
{ ... }
这意味着此枚举应使用short作为基础类型来表示其枚举成员。所有枚举类型都是从Enum类派生的,因此调用GetTuples不会使用您提供的代码进行编译,但会编译GetTuples

这就是为什么你的样品不能按你的预期工作

您可以通过删除继承约束并在运行时检查基础类型来修复GetTuples方法:

public static IEnumerable<Tuple<TEnum, TBase>> GetTuples<TEnum, TBase>()
       where TEnum : struct, IConvertible
{
    Type tEnumType = typeof(TEnum);
    if (!tEnumType.IsEnum || Enum.GetUnderlyingType(tEnumType) != typeof(TBase))
    {
        throw new ArgumentException("Invalid type specified.");
    }
    return GetValues<TEnum>().Select(x => new Tuple<TEnum, TBase>(x, (TBase)Convert.ChangeType(x, typeof(TBase))));
}
现在您应该能够调用EnumUtilities.GetTuples;它应该正确编译


此解决方案的缺点是运行时检查的效率低于使用编译时约束。

您的EnumType是从short继承的,默认情况下,short是从Enum继承的,因此在使用EnumType值时,可以显式地将EnumType值强制转换为short。另一种方法是在初始化时将值转换为short,如下所示

public enum EnumType : short
{
    Value1 = (short)1,
    Value2 = (short)2
}
在这种情况下,在使用时不需要强制转换。

试试这个

public static class EnumUtilities
{
    public static IEnumerable<Tuple<TEnum, object>> GetTuples<TEnum>() where TEnum :    struct, IConvertible
    {
        if (!typeof(TEnum).IsEnum)
           throw new Exception("wrong!");

        return GetValues<TEnum>().Select(x => new Tuple<TEnum, object>(x, Convert.ChangeType(x, x.GetTypeCode())));
    }

    public static IEnumerable<T> GetValues<T>() where T : struct, IConvertible
    {
         if (!typeof(T).IsEnum)
            throw new Exception("wrong!");

         return Enum.GetValues(typeof(T)).Cast<T>();
    }
}

默认情况下,枚举的类型是int。因此不可能隐式转换为short。当然,这是理解的关键:问题是,枚举类型不是从short派生的。
public static class EnumUtilities
{
    public static IEnumerable<Tuple<TEnum, object>> GetTuples<TEnum>() where TEnum :    struct, IConvertible
    {
        if (!typeof(TEnum).IsEnum)
           throw new Exception("wrong!");

        return GetValues<TEnum>().Select(x => new Tuple<TEnum, object>(x, Convert.ChangeType(x, x.GetTypeCode())));
    }

    public static IEnumerable<T> GetValues<T>() where T : struct, IConvertible
    {
         if (!typeof(T).IsEnum)
            throw new Exception("wrong!");

         return Enum.GetValues(typeof(T)).Cast<T>();
    }
}