为什么不会通过这种通用方法调用编译?

时间:2014-10-02 18:17:41

标签: c# generics enums

我是一个简短的枚举:

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

当我尝试调用它时,我收到一个编译错误,说“Type EnumType必须可以转换为'short',以便在泛型方法'IEnumerable&gt; GetTuples()'中使用它作为参数'TEnum'

我很难理解,当定义为“短”时,EnumType不能转换为'short'。我也不理解以下编译方式,但上面的例子没有。任何帮助表示赞赏!

var enumType = EnumType.Value1;
var value1 = (short)enumType;

3 个答案:

答案 0 :(得分:4)

问题的原因在于您编写的GetTuples<,>()泛型方法约束

TEnum: struct, TBase

这意味着TEnum应该来自TBase的派生类型。我想你试图或多或少地称之为:EnumUtilities.GetTuples<EnumType, short>()问题是EnumType不是来自short

你宣布它的方式:

public enum EnumType: short
{ ... }

表示只应将short用于此枚举作为表示其枚举成员的基础类型。所有枚举类型都派生自Enum类,因此调用GetTuples<EnumType, short>将无法使用您提供的代码进行编译,但GetTuples<EnumType, Enum>将进行编译。

这就是为什么您的样本无法按预期工作的原因。

您可以通过删除继承约束并在运行时检查基础类型来修复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>();并且它应该正确编译。

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

答案 1 :(得分:0)

您的EnumType继承自short,默认情况下是Enum,因此将EnumType值强制显示为short,而使用它时工作正常。另一种方法是在初始化时将值转换为short,如下所示。

public enum EnumType : short
{
    Value1 = (short)1,
    Value2 = (short)2
}

在这种情况下,使用时不需要施放。

答案 2 :(得分:0)

试试这个

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