Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
215 views
in Technique[技术] by (71.8m points)

c# - Why can't I give a default value as optional parameter except null?

I want to have a optional parameter and set it to default value that I determine, when I do this:

private void Process(Foo f = new Foo())
{

}

I'm getting the following error (Foo is a class):

'f' is type of Foo, A default parameter of a reference type other than string can only be initialized with null.

If I change Foo to struct then it works but with only default parameterless constructor.

I read the documentation and it's clearly states that I cannot do this but it doesn't mention why?, Why is this restriction exists and why string is excluded from this? Why the value of an optional parameter has to be compile-time constant? If that wouldn't be a constant then what would be the side-effects ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A starting point is that the CLR has no support for this. It must be implemented by the compiler. Something you can see from a little test program:

class Program {
    static void Main(string[] args) {
        Test();
        Test(42);
    }
    static void Test(int value = 42) {
    }
}

Which decompiles to:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldc.i4.s   42
  IL_0002:  call       void Program::Test(int32)
  IL_0007:  ldc.i4.s   42
  IL_0009:  call       void Program::Test(int32)
  IL_000e:  ret
} // end of method Program::Main

.method private hidebysig static void  Test([opt] int32 'value') cil managed
{
  .param [1] = int32(0x0000002A)
  // Code size       1 (0x1)
  .maxstack  8
  IL_0000:  ret
} // end of method Program::Test

Note how there is no difference whatsoever between the two call statements after the compiler is done with it. It was the compiler that applied the default value and did so at the call site.

Also note that this still needs to work when the Test() method actually lives in another assembly. Which implies that the default value needs to be encoded in the metadata. Note how the .param directive did this. The CLI spec (Ecma-335) documents it in section II.15.4.1.4

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]

The quoted section II.22.9 goes into the detail of what a constant value means. The most relevant part:

Type shall be exactly one of: ELEMENT_TYPE_BOOLEAN, ELEMENT_TYPE_CHAR, ELEMENT_TYPE_I1, ELEMENT_TYPE_U1, ELEMENT_TYPE_I2, ELEMENT_TYPE_U2, ELEMENT_TYPE_I4, ELEMENT_TYPE_U4, ELEMENT_TYPE_I8, ELEMENT_TYPE_U8, ELEMENT_TYPE_R4, ELEMENT_TYPE_R8, or ELEMENT_TYPE_STRING; or ELEMENT_TYPE_CLASS with a Value of zero

So that's where the buck stops, no good way to even reference an anonymous helper method so some kind of code hoisting trick cannot work either.

Notable is that it just isn't a problem, you can always implement an arbitrary default value for an argument of a reference type. For example:

private void Process(Foo f = null)
{
    if (f == null) f = new Foo();

}

Which is quite reasonable. And the kind of code you want in the method instead of the call site.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...