Implementing an Interface with Additional Arguments

Take this interface:

interface ILogger { void Store(string payload); } 

And this implementation of the ILogger class:

 class Logger : ILogger { void Store(string payload, bool swallowException = true) { ... } } 

I expected the compiler to recognize swallowException as an optional argument, and thus satisfy the interface requirements. Instead, the compiler complains that Logger does not implement a member of the Store interface.

Another interesting thing I've tried is to implement the interface explicitly:

 class Logger : ILogger { void ILogger.Store(string payload, bool swallowException = true) { ... } } 

The compiler gives the warning "The default value specified for the" swallowException "parameter will have no effect, because it applies to the member that is used in contexts that do not allow optional arguments." It seems that the optional arguments are somehow incompatible with explicit interface definitions, but why?

I can get around the problem by overloading the Store with two separate function definitions (a way to do something before the optional arguments exist). However, I like the optional arguments for their syntactic clarity, and would prefer it to work as I expect.

I understand that perhaps a reasonable (historical or other) explanation of why it is, but I cannot understand how to understand it.

+6
source share
1 answer

Because the extra arguments in C # are just syntactic sugar.

Method definition in your case

 void Store(string payload, bool swallowException) 

but not

 void Store(string payload) 

Which clearly does not match the interface.

The default use case is that the compiler enters default values โ€‹โ€‹into a method call. Therefore, if you execute Store(payload) , the compiler actually issues Store(payload, true) . This is very important for understanding the default arguments - this is done during compilation of the caller. Therefore, if you change the default argument in the called call without recompiling the caller, the caller will still use the old default argument.

This also explains the warning you received - since the default value is passed explicitly by the compiler, and you cannot invoke an explicit implementation of the interface without casting to the interface, you will not be able to use the default value.

In fact, you donโ€™t want to use the default arguments at all. Just define two methods:

 void Store(string payload, bool swallowException) { // Do your job } void Store(string payload) { Store(payload, true); } 

This avoids both of the above problems - the interface contract is satisfied, and the default argument is now part of the called party, not the calling party.

Personally, I donโ€™t use optional arguments at all in public API methods - they just hurt to cause problems when you decide that you want to change them at some point. If you cannot make sure that they remain unchanged forever, do not use them. The same goes for const and enum - both of them are also defined at compile time, and not at run time.

Remember that the argument argumentation by default is to allow you not to pass any argument. This makes sense for things like COM API calls (which otherwise would require passing all arguments that you don't want to pass as Type.Missing ), or null values. Even when using false , a problem simply arises when someone decides that the best default value is true - suddenly some callers use true and some false , although everyone thinks that they use "default". For a case like yours, would I use bool? instead bool? with a default value of null (or default(bool?) , depending on what you prefer). In the method code itself, you can easily handle the default value at the correct point - for example, by executing swallowException.GetValueOrDefault(true) .

+11
source

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


All Articles