在c#中将Int转换为泛型可空枚举

本文关键字:泛型 枚举 转换 中将 Int | 更新日期: 2023-09-27 18:17:59

我想将int值强制转换为使用泛型函数的可空枚举。我认为这很容易,特别是所有关于enum/int类型转换的所有SO。我发现的最接近的问题是这个,但不幸的是,它不处理可空枚举。这个问题解决了可空枚举的强制转换问题,但不解决泛型。

下面是我要做的一个简化的例子:

public enum SouthParkCharacters
{
    Stan = 0,
    Kyle = 1,
    Eric = 2,
    Kenny = 3
}
public static T CastNullableEnum<T>(int value)
{
    return (T)(object)((int?)value).Value;
}

public static T SomeFunction<T>(this int anyEnumValue)
{
        SouthParkCharacters? spc = SouthParkCharacters.Kenny;
        spc = CastNullableEnum<SouthParkCharacters>(3); //I am working!
        spc = CastNullableEnum<SouthParkCharacters?>(3); //Raise error Specified cast is not valid.
        //This function will be public so I won't have control over the T
        T finalValue = CastNullableEnum<T>(anyEnumValue); //Raise error Specified cast is not valid.
        return finalValue;
}

在最后一个函数中可以看到,对非空枚举的强制转换正在起作用。问题是,我希望能够从另一个泛型函数调用CastNullableEnum,该泛型函数可以使用可空枚举作为泛型类型。

我知道你可以传递一个泛型类型作为一个可空的泛型CastNullableEnum<T?>,但我们可以做相反的(即传递可空的底层类型到泛型函数)?

如果这不能做到,那么我想解决方案是找到正确的方法来在CastNullableEnum函数中转换enum值。

在c#中将Int转换为泛型可空枚举

我可能读错了这个问题,但是您可以从可空对象中获取底层类型,并使用Enum.Parse而不是直接强制转换。

public T CastNullableEnum<T>(int value) 
{
    var enumType = Nullable.GetUnderlyingType(typeof(T));
    if (Enum.IsDefined(enumType, value)) 
    {
        return (T)(object)Enum.Parse(enumType, value.ToString());
    }
    return default(T);
}
var test1 = CastNullableEnum<SouthParkCharacters?>(3); 
//returns Kenny
var test2 = CastNullableEnum<SouthParkCharacters?>(9); 
// returns null

可以:

public static T IntToEnum<T>(object value)
{
    if (value == null)
        return (T)value;
    else if (typeof(T).IsEnum)
        return (T)value;
    else if (Nullable.GetUnderlyingType(typeof(T))?.IsEnum == true)
        return (T)Enum.ToObject(Nullable.GetUnderlyingType(typeof(T)), (int)value);
    throw new Exception(string.Format("Value cannot be converted from {0} to {1}", value.GetType().Name, typeof(T).Name));
}

可用于可空枚举和常规枚举

public enum Codes
{
    A = 1,
    B = 2,
    C = 3
}
static void Main(string[] args)
{
    Console.WriteLine(IntToEnum<Codes?>(1));
    Console.WriteLine(IntToEnum<Codes?>(null));
    Console.WriteLine(IntToEnum<Codes>(2));
}

有趣的问题。此代码的问题是将整型转换为可空的enum,这是不可能的。

  SouthParkCharacters? enumValue = (SouthParkCharacters?)int.MaxValue;
  if (enumValue.HasValue)
     {
         Console.WriteLine("it still has value");
     }

上面的代码正在运行,它的结果仍然是枚举值HasValue。

但是无论如何,如果你在编译后看一下c#代码,它会是这样的:
public static T CastNullableEnum<T>(int value)
    {
        Type type = typeof(T);
        return (T)((object)value);
    }
    public static T SomeFunction<T>(int anyEnumValue)
    {
        Program.SouthParkCharacters? spc = new Program.SouthParkCharacters?(Program.SouthParkCharacters.Kenny);
        spc = new Program.SouthParkCharacters?(Program.CastNullableEnum<Program.SouthParkCharacters>(new int?(3)));
        spc = Program.CastNullableEnum<Program.SouthParkCharacters?>(new int?(3));
        return Program.CastNullableEnum<T>(new int?(anyEnumValue));
    }

注意

spc = new Program.SouthParkCharacters?(Program.CastNullableEnum<Program.SouthParkCharacters>(new int?(3))); 

这就是未指定强制转换异常的来源;因为南方公园的新角色?(int value)期望一个整型值

有趣的是,当你运行Immediate时,你不会遇到这个问题。很有趣,不是吗?