c# - 通过反射获取可选 Guid 的默认值?

标签 c# reflection optional-parameters value-type base-class-library

我有以下代码,用作说明不同场景的示例:

    public static void MethodWithOptionalGuid(Guid id = default(Guid)) { }

    public static void MethodWithOptionalInteger(int id = 2) { }

    public static void MethodWithOptionalString(string id = "33344aaa") { }

    public static void MethodWithoutOptionalParameter(int id, Guid longId) { }

    static void Main(string[] args)
    {
        var methods = typeof(Program).GetMethods(BindingFlags.Public | BindingFlags.Static).ToList();

        foreach (var method in methods)
        {
            PrintMethodDetails(method);
        }

        Console.ReadLine();
    }

    static void PrintMethodDetails(MethodInfo method)
    {
        Console.WriteLine(method.Name);

        foreach (var parameter in method.GetParameters().ToList())
        {
            Console.WriteLine(parameter.Name +
                              " of type " + parameter.ParameterType.ToString() +
                              " with default value:" + parameter.DefaultValue);
        }

        Console.WriteLine();
    }

打印如下:

MethodWithOptionalGuid
id of type System.Guid with default value:

MethodWithOptionalInteger
id of type System.Int32 with default value:2

MethodWithOptionalString
id of type System.String with default value:33344aaa

MethodWithoutOptionalParameter
id of type System.Int32 with default value:
longId of type System.Guid with default value:

最后 3 种方法的输出似乎没问题。

我的问题是关于第一个问题,MethodWithOptionalGuid:为什么无法识别 Guid 的默认值?

我希望收到类似 "0000000-..."的信息。我还尝试使用 new Guid() 和相同的结果初始化可选参数。我也尝试了其他结构,例如 TimeSpan,并且行为是相同的。

我希望所有值类型的行为都相同(如整数示例所示)。

额外:我在尝试在 Asp.Net MVC 中使用带有可选 Guid 参数的操作时发现了这个东西,但失败了(必须使 Guid 可为空)。浏览 MVC 代码,发现它在某些时候使用了 DefaultValue。所以我做了这个代码示例来更好地说明我的问题。

最佳答案

原因 非常相关,当您想做这样的事情时,您确实需要注意这一点。龙住在这里。如果您使用 ildasm.exe 查看该方法,您将看到:

  .param [1] = nullref

结构 类型的默认值是 null,呃哦。 .param 指令的语义在 CLI 规范 Ecma-335 第 II.15.4.1.4 章中进行了描述。它很短,我将复制粘贴整个章节(为了便于阅读而编辑)

MethodBodyItem ::= .param ‘[’ Int32 ‘]’ [ ‘=’ FieldInit ]

This directive stores in the metadata a constant value associated with method parameter number Int32, see §II.22.9. While the CLI requires that a value be supplied for the parameter, some tools can use the presence of this attribute to indicate that the tool rather than the user is intended to supply the value of the parameter. Unlike CIL instructions, .param uses index 0 to specify the return value of the method, index 1 to specify the first parameter of the method, index 2 to specify the second parameter of the method, and so on.

[Note: The CLI attaches no semantic whatsoever to these values—it is entirely up to compilers to implement any semantic they wish (e.g., so-called default argument values). end note]

[Note] 最相关。当你使用反射时,你扮演了编译器的角色,正确解释默认值取决于你。换句话说,您必须知道在 C# 中,结构类型的默认值为 null

否则,这是对可以存储在 [FieldInit] 中的内容的限制。初始化值必须存储在程序集的元数据中,并受到与 [attribute] 声明相同类型的限制。只能使用简单的值类型,不能使用结构。因此,按照惯例,C# 设计人员通过使用 null 来解决这个问题。足以让 C# 编译器理解 default(Guid) 的意图。

问题还不止于此,还有其他方法指示可选参数,[OptionalAttribute] 在 C# v4.0 之前使用。直到今天,COM 互操作库和其他语言(如 VB.NET 和 C++/CLI)仍在使用它。那是龙居住的地方。

暂时忽略那些野兽,你所拥有的解决方法代码可能如下所示:

    var def = parameter.DefaultValue;
    if (parameter.ParameterType.IsValueType && def == null) {
        def = Activator.CreateInstance(parameter.ParameterType);
    }
    Console.WriteLine(parameter.Name +
                      " of type " + parameter.ParameterType.ToString() +
                      " with default value:" + def);

关于c# - 通过反射获取可选 Guid 的默认值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36173391/

相关文章:

.net - 如何为通过 Reflection.Emit 创建的类型指定命名空间?

c# - AspNetUsers (Identity) 和自定义表之间的一对多关系

c# - 获取数组中特定项目的索引

c# - 将 IronPython 嵌入到我的 C# 应用程序中的最佳方式是什么?

c# - 有没有一种简单的方法可以将对象属性转换为字典<string, string>

c# - 程序集.加载+依赖项

ios - 如何在 Swift 协议(protocol)中定义可选方法?

Python:使用位置参数之前的默认参数调用函数

c# - C#中Javascript异常消息

C++:默认参数和 vector