I was surprised that C# uses a value for optional method argument of interface, not from class implementing this interface. For example:
using System;
public class Program
{
private static IMyInterface instance;
public static void Main()
{
instance = new MyClass();
instance.PrintOpt();
((MyClass)instance).PrintOpt();
}
}
public interface IMyInterface
{
void PrintOpt(bool opt = false);
}
public class MyClass : IMyInterface
{
public void PrintOpt(bool opt = true)
{
Console.WriteLine($"Value of optional argument is {opt}");
}
}
produces output:
Value of optional argument is False
Value of optional argument is True
My question is: is it possible to define an optional parameter in an interface without default value or "overridable", so calling of method on instance saved in variable of interface type uses a optional value defined in a class implementing this interface?
When you call the method in the class you have to follow the class rules (the parameter is not optional in the class so you can't call the method without it), and in the second hand when you implement the interface you have to follow the interface rules,so you can override the methods with/without optional parameters.
OptionalAttribute parameters do not require a default value.
The thing with optional parameters is, they are BAD because they are unintuitive - meaning they do NOT behave the way you would expect it. Here's why: They break ABI compatibility ! so you can change the default-arguments at one place.
You can define Python function optional arguments by specifying the name of an argument followed by a default value when you declare a function. You can also use the **kwargs method to accept a variable number of arguments in a function. To learn more about coding in Python, read our How to Learn Python guide.
This wouldn't be surprising if you understood how optional arguments are handled internally: they are inlined during compilation.
In other words, at the place where a method is called, any optional arguments are passed by the compiler - if you're calling an interface method, the compiler has no idea that there's an implementation with a different optional argument. The difference is best seen with code like this:
IMyInterface interface = new MyClass();
MyClass theClass = (MyClass)interface;
interface.PrintOpt(); // false
theClass.PrintOpt(); // true
Which is compiled to this (translated back to C#):
interface.PrintOpt(false);
theClass.PrintOpt(true);
The "default" arguments are no longer "default" in the IL code - they are just another explicitly passed argument.
If you want to use optional arguments that are overridable, just use method overloads. Or better, use default values that don't mean anything (e.g. null
or default(int?)
) and do any replacing for defaults inside of the method. This is in line with the original reason for including optional arguments to C# in the first place - VB-style COM interfaces often have methods with dozens of arguments, almost all of which are optional. Until now, when you wanted to call a method like this, you had to do something like
comInterface.MyMethod(TheActualArgumentICareAbout, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, ...);
Now you can just do
comInterface.MyMethod(argument, anotherSuperUseful: true);
This distinction is a big deal - it also means that you shouldn't ever change default arguments on any public method. Anyone using your library without recompiling will still use the old default value. It's similar to how const
values or enums are handled. If you use a null
for a default instead, the actual default value will be inside the method itself, and all callers will "see" the correct default even if they don't recompile (similar to using a public static readonly
field instead of const
, or a class with properties instead of an enum).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With