C # method with default value does not generate overload without parameter?

Recently, I wanted to add an optional parameter to an extension method. The original method looked like this:

public static class Extensions { public static bool Foo(this IFoo target) { target.DoIt(true); } } 

This is obviously a simplified version, but release it.

What I've done:

 public static class Extensions { public static bool Foo(this IFoo target, bool flag = true) { target.DoIt(flag); } } 

All I did was enter an optional parameter with a default value, right? I expected the compiler to generate an overloaded method without a flag. This has partially happened. Any code that I recompiled was able to compile and execute without any problems, even without this parameter:

 ... IFoo foo = new FooBar(); foo.Foo(); ... 

However, any code that was created against the previous version of Foo () did not work, throwing the following exception:

 Unhandled Exception: System.MissingMethodException: Method not found: 'Boolean Models.Class1.Foo()'. at DefaultParamsTests.Program.Main(String[] args) 

This is obviously a problem for us, since we have a public API that our customers use, and it will be a terrific change.

The solution is to explicitly create an overload:

 public static class Extensions { public static bool Foo(this IFoo target) { target.DoIt(true); } public static bool Foo(this IFoo target, bool ) { target.DoIt(true); } } 

However, Resharper assumes that I can enter an optional parameter for the foo method.

resharper introduce optional parameter

If I follow refactoring, it basically does what I showed above. However, this will not work for existing code.

resharper refactored

I looked at the generated IL using Reflector and dotPeek. Overload generation is not displayed.

What am I missing?

+5
source share
3 answers

For default settings, the actual call site is overwritten to use the default value. This means that no overload is generated at all, your calling code has been changed!

 public void fun(int x = 3) { } // in another file fun(); // compiler re-writes to fun(3); fun(7); // fun(7) as expected // actual code generated by the c# compiler fun(3); fun(7); 

If you use optional parameters in C #, you need to recompile all callers when function changes. For this reason, it is strongly discouraged to use such methods in an open interface (for example, called by other code). Using them inside your own related projects is great, as they must compile everything at the same time.

+4
source

Additional parameters in C # methods are allowed at compile time on the call site. Your call code, which omits the parameter, expands to include the parameter, invoking the two-parameter version. This is the opposite of what you assume with the creation of overload.

+4
source

The key point here is that the compiler changes the calling method to include the default value.

Take a look at the new code in dotPeek.

NOTE. You must delete pdb files when using dotPeek in your files!

Here is an extension class with two methods (decompiled using dotPeek). One with default and one without

 public static class Extensions { public static bool Foo(this IFoo target) { return target.DoIt(true); } public static bool Foo(this IFoo2 target, bool doit = false) { return target.DoIt2(doit); } } 

Everything is fine there. Now let's look at the object that calls the extension method (decompiled with dotPeek).

 public class Bar { public Bar(IFoo foo) { Extensions.Foo(foo); } public Bar(IFoo2 foo) { Extensions.Foo(foo, false); } } 

Note that the caller for the IFoo2 extension method actually contains false for the Foo method of the class extensions. Thus, your Extensons.Foo method now has two parameters in it. The first method is an object, and the second is the default parameter. Thus, any code that was created with the first version will fail, because there is no method with only one parameter.

Disable the reconfiguration of the methods and you will no longer see how it bothers you the most :)

+1
source

Source: https://habr.com/ru/post/1212075/


All Articles