【问题标题】:Strange behaviour of Enum.GetNameEnum.GetName 的奇怪行为
【发布时间】:2014-02-07 18:08:52
【问题描述】:

我有一个这样的枚举:

public enum MyEnum
{
    Character = 'C',
    Number = 'N',
}

然后我正在做这样的事情:

char myChar = 'C';
var value = Enum.GetName(typeof(MyEnum), myChar); //throw exception on .NET 3.5 or less

此代码在使用 .NET 4 的项目中是可以的,但在 .NET 3.5 或更低版本上会引发异常。这是一个例外:

传入的值必须是枚举基类或基础类型 枚举,例如一个 Int32。参数名称:值

所以我使用 .NET 4 发布了我的项目,并与我的朋友分享并告诉他们他们需要 .NET4。他们成功运行了程序但发现程序在某些系统上即使使用 .NET 4 也会引发相同的异常!有人知道这个异常的原因是什么吗?

我通过这种方式解决了这个问题,但想知道为什么它在某些系统上有效,而在其他一些系统上无效? (他们都有.NET4)

var value = Enum.GetName(typeof(MyEnum), (int)myChar);

【问题讨论】:

  • 错误信息的哪一部分你不明白?您需要传递一个数字。
  • 但它在某些系统上的 .NET 4 中工作。
  • 你能比较一下哪些系统可以工作,哪些不可以吗?如果它在安装了 .NET 4.5 的那些系统(并且仅限于那些系统)上运行,我不会感到惊讶。尽管您的目标是 4.0,但 4.5 是一种就地升级,有一些细微的行为变化。
  • C#/VB.NET 中隐式转换的微妙之处...
  • @hvd 不幸的是,我现在无法访问这些系统。获取有关它们的信息需要一些步骤...

标签: c# .net-4.0 exception-handling enums


【解决方案1】:

这在 .NET 4.5 中已更改。请注意,很难看出您的机器上安装的是 4.0 还是 4.5,4.5 替换 4.0 并使用与 4.0 相同的安装目录。

更改的方法是@Dirk 引用的方法,即内部 IsIntegerType() 辅助方法。 4.0版本长这样:

internal static bool IsIntegerType(Type t)
{
    if (((!(t == typeof(int)) && !(t == typeof(short))) && (!(t == typeof(ushort)) && 
          !(t == typeof(byte)))) && ((!(t == typeof(sbyte)) && !(t == typeof(uint))) && 
          !(t == typeof(long))))
    {
        return (t == typeof(ulong));
    }
    return true;
}

注意 typeof(char) 没有经过测试,因此它不会认为它是您传递给 Enum.GetName() 的 value 参数的有效类型。

.NET Framework 版本中的这些不是并行版本的更改相当不酷,它确实使诊断程序故障变得非常困难。特别是因为您在项目中针对 NET 4.0,但最终在安装了 4.5 的机器上运行,所以从未注意到这个问题。但是kaboom在只安装了4.0的机器上。

最好的说法是,这是 4.0 中的一个错误,他们在 4.5 中修复了。坦率地说,您当然希望 char 完全有效,因为这是您用来初始化枚举成员的。它确实显示了微软修复错误是多么困难。

【讨论】:

  • 4.5 程序集在 GAC 中是否也显示为 4.0.0.0?我试图找到它们,但无法使用 ILSpy 找到它们。
  • 是的,它们的版本号仍然是 4.0.0.0。只有 4.5 中添加的版本号为 4.5.0.0。我不得不从旧机器上复制 4.0 版本的 mscorlib.dll 来写这个答案。
【解决方案2】:

Enum.GetName 的实现从 2.0 更改为 4.0。

这是 2.0 的反编译版本(带有 ILSpy):

public static string GetName(Type enumType, object value)
{
    [...]
    // Enum.intType = typeof(int)
    Type type = value.GetType();
    if (type.IsEnum || type == Enum.intType || type == typeof(short) || type == typeof(ushort) || type == typeof(byte) || type == typeof(sbyte) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong))
    {
        return Enum.InternalGetValueAsString(enumType, value);
    }
    throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
}

你可以看到type = typeof(char)这个异常被抛出了。


对于 4.0,它是:

public static string GetName(Type enumType, object value)
{
    [...]
    // this is actually in a method called by GetName, I put it here for clarity
    Type type = value.GetType();
    if (!type.IsEnum && !Type.IsIntegerType(type))
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
    }
    [...]
}

// Type.IsIntegerType
internal static bool IsIntegerType(Type t)
{
    return t == typeof(int) || t == typeof(short) || t == typeof(ushort) || t == typeof(byte) || t == typeof(sbyte) || t == typeof(uint) || t == typeof(long) || t == typeof(ulong) || t == typeof(char) || t == typeof(bool);
}

但是这里type = typeof(char) 不会导致异常。

【讨论】:

  • 这仍然没有回答为什么它会在某些使用 .NET 4 的系统上引发异常。
  • @hvd 我发现这种异常的唯一地方都有相同的 if-check。发生异常时,您确定使用 .NET 4.0 运行时执行它吗?
  • 我不是 OP,我只是重复 OP 在您发布答案之前已经澄清的内容:)
  • @hvd 我不应该假设。对不起。
  • @Dirk 有用的答案。如何引导我的朋友找出运行程序的 CLR?
【解决方案3】:

枚举的批准类型是 byte, sbyte, short, ushort, int, uint, long, or ulong MSDN

您不能创建 Enum char 值,.NET 允许您这样做,但编译器会将您的 char 值转换为其等效的 int 表示 (ASCII)。

【讨论】:

  • 在我的 .NET 4 系统上,我也可以发送字符(当发送“C”到GetName 时,它返回“字符”),没有问题。
  • 没错,但他没有将字符用于枚举底层值,他只将值设置为“C”和“N”的整数值。
  • 主要问题是为什么它在某些系统上有效而在其他一些系统上无效(都具有.NET 4)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 2015-07-20
  • 2010-10-03
  • 2021-07-12
  • 2013-10-04
  • 2019-01-23
相关资源
最近更新 更多