考虑以下示例:

class Program
{
    static void Main(string[] args)
    {
        foreach(var par in typeof(A).GetMethod("Method").GetParameters())
        {
            Console.WriteLine("Def {0}, RawDef {1}",
                par.DefaultValue, par.RawDefaultValue);
        }
    }
}

class A
{
    public void Method(int a = 5, B b = B.b){}
}
enum B
{
    a = 0, b = 1
}

根据 RawDefaultValue DefaultValue 的文档,在 StackOverflow 的支持下,这两种访问默认值的方法应该返回相同的数据。

但相反,我得到以下输出:
Def 5, RawDef 5
Def b, RawDef 1

因此,显然 RawDefaultValue 删除了有关参数为枚举类型的信息。

我的问题:这是一个错误还是由文档的另一部分证明是合理的?

有趣的事实:在 Mono 上它返回
Def 5, RawDef 5
Def b, RawDef b

最佳答案

tl;dr:这不是错误,而是功能...

正如您在文档中所见, RawDefaultValue 支持仅反射上下文,而 DefaultValue 不支持。

现在,如果我们检查这两个方法的源代码,我们将看到它使用 System.Reflection.MdConstant 标志调用 GetValue 的方法 bool raw 方法。

由于 System.Reflection 希望根据其所处的上下文为您提供“最佳”信息,因此它宁愿为您提供 enum 而不是原始值(原始值可以从 enum 字段得出,反之则不然工作)。

现在我们可以在 System.Reflection.MdConstant.GetValue 中看到:

if (fieldType.IsEnum && raw == false)
{
    ...
    switch (corElementType) //The actual enum value
    {
        ...
        case CorElementType.I4:
            defaultValue = *(int*)&buffer;
            break;
        ...
    }
    return RuntimeType.CreateEnum(fieldType, defaultValue);
}

在您的情况下返回 B.b // = 1

但是调用 RawDefaultValue 会使标志 false 使其成为:
switch (corElementType)
{
    ...
    case CorElementType.I4:
        return *(int*)&buffer;
    ...
}

在您的情况下返回 1

如果您尝试使用 System.RuntimeType.CreateEnum 调用 Reflection (因为它是内部的),使用加载的 Assembly 仅反射上下文,您将获得 InvalidOperationException :
//Change to 'Assembly.Load' so the last line will not throw.
Assembly assembly = Assembly.ReflectionOnlyLoad("DllOfB");

Type runtimeType = Type.GetType("System.RuntimeType");
MethodInfo createEnum = runtimeType.GetMethod("CreateEnum", /*BindingFlags*/);

MethodInfo getRuntimeType = typeof(RuntimeTypeHandle).GetMethod("GetRuntimeType", /*BindingFlags*/);
Type bType = assembly.GetType("DllOfB.B");

//Throws 'InvalidOperationException':
object res = createEnum.Invoke(null, new [] { getRuntimeType.Invoke(bType.TypeHandle, new object[]{}), 1 });

至于 Mono 支持从 B.b 返回 RawDefaultValue 这意味着 Mono 不支持 DefaultValue 用于仅反射上下文 或者它可以以某种方式从 Type 创建 Assembly 的实例,这可能在不同的体系结构中 - 其中不太可能。

关于c# - Enum 参数的 DefaultValue 和 RawDefaultValue 出现意外差异,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40887723/

10-11 15:31