为什么可选参数的默认值必须由常量表达式或值类型的无参数构造函数指定?
Why the default value of an optional parameter must be specified by a constant expression, or a parameterless constructor of a value type?
我知道可选参数的默认值必须由常量表达式或值类型的无参数构造函数指定。但我不知道为什么!为什么我们不能使用其他任何东西?谁能帮我解释一下原因?
C# 的创建者决定可选方法参数不应使 classes 的二进制接口复杂化,这意味着它们应该是纯源代码的,syntactic-sugar 功能,利用语言中预先存在的任何其他机制,而不添加任何新内容。
这意味着,一方面,给定方法参数的默认值表达式必须在编译每次调用方法时完全可解析。
但是如果 class 已知,此要求仍然不会阻止您实例化 class 作为默认值传递给参数。所以,实际情况要复杂一些。
在像 C# 这样的语言中,当您只有 DLL 而没有源代码时,总是可以针对程序集进行编程。因此,"source-code-only" 功能从来都不是纯源代码。为了向语言添加可选的方法参数,他们不得不引入一个小技巧:在方法的定义中,对于每个可选参数,编译器都会发出一个特定的属性,其内容指定参数的默认值应该是什么是。该属性在运行时不使用,仅在编译时使用。因此,当您编写对该方法的调用并省略可选参数时,编译器会在目标程序集中查找可选参数属性,并知道它应该传递什么值。
但是C#中的属性也有这样的限制:它们的所有参数都必须是编译时常量。 (参见 ECMA-335 第二部分 §21 "Custom attributes" 和第二部分 §23.3 "Custom attributes"。)
因此,最终,为什么默认参数值必须是编译时常量这个问题的答案是因为它们的实现涉及在幕后使用属性,而属性参数又必须是编译时常量。
为什么属性参数必须是编译时常量的技术解释基本上是因为该语言的创建者不想让事情变得太复杂。属性参数必须非常简单,可以将它们转换为字节数组并放入二进制文件中,并且在加载 class 时,这个字节数组必须非常容易地转换为一组参数以传递给属性。对于它的价值,Java 完全相同,其中 "attributes" 被称为 "annotations"。
但这并不完全正确。可以使用 ConstantAttribues 来定义。
Jon Skeet 写了一个很好的 blogpost 关于它。
本质上您还可以执行以下操作:
public void PrintDateTime([Optional, DateTimeConstant(635443315962469079L)] DateTime date)
{
Console.WriteLine(date);
}
我知道可选参数的默认值必须由常量表达式或值类型的无参数构造函数指定。但我不知道为什么!为什么我们不能使用其他任何东西?谁能帮我解释一下原因?
C# 的创建者决定可选方法参数不应使 classes 的二进制接口复杂化,这意味着它们应该是纯源代码的,syntactic-sugar 功能,利用语言中预先存在的任何其他机制,而不添加任何新内容。
这意味着,一方面,给定方法参数的默认值表达式必须在编译每次调用方法时完全可解析。
但是如果 class 已知,此要求仍然不会阻止您实例化 class 作为默认值传递给参数。所以,实际情况要复杂一些。
在像 C# 这样的语言中,当您只有 DLL 而没有源代码时,总是可以针对程序集进行编程。因此,"source-code-only" 功能从来都不是纯源代码。为了向语言添加可选的方法参数,他们不得不引入一个小技巧:在方法的定义中,对于每个可选参数,编译器都会发出一个特定的属性,其内容指定参数的默认值应该是什么是。该属性在运行时不使用,仅在编译时使用。因此,当您编写对该方法的调用并省略可选参数时,编译器会在目标程序集中查找可选参数属性,并知道它应该传递什么值。
但是C#中的属性也有这样的限制:它们的所有参数都必须是编译时常量。 (参见 ECMA-335 第二部分 §21 "Custom attributes" 和第二部分 §23.3 "Custom attributes"。)
因此,最终,为什么默认参数值必须是编译时常量这个问题的答案是因为它们的实现涉及在幕后使用属性,而属性参数又必须是编译时常量。
为什么属性参数必须是编译时常量的技术解释基本上是因为该语言的创建者不想让事情变得太复杂。属性参数必须非常简单,可以将它们转换为字节数组并放入二进制文件中,并且在加载 class 时,这个字节数组必须非常容易地转换为一组参数以传递给属性。对于它的价值,Java 完全相同,其中 "attributes" 被称为 "annotations"。
但这并不完全正确。可以使用 ConstantAttribues 来定义。 Jon Skeet 写了一个很好的 blogpost 关于它。
本质上您还可以执行以下操作:
public void PrintDateTime([Optional, DateTimeConstant(635443315962469079L)] DateTime date)
{
Console.WriteLine(date);
}