I think that trying to solve the issue introduced by default parameters using other overloads with default parameters is just booking for more troubles in future...
Non-breaking change: what I'd do is to add a new method with a different name and keep the old method as-is. Callers of the old interface won't be affected by this change and new users will have the fully featured new method available.
public void MyMethod(int a = 0) {
MyBetterMethod(a, 1);
}
public void MyBetterMethod(int a, int b) { }
Migrate from old syntax: mark the old method [Obsolete]
(and remove it in a future version). Do not forget to suggest the right method to use in the warning message.
Keep it as warning for few versions:
[Obsolete("This method is obsolete, use MyBetterMethod() instead.")]
public void MyMethod(int a = 0){}
With your next major release make it a compile-time error:
[Obsolete("This method is obsolete, use MyBetterMethod() instead.", true)]
public void MyMethod(int a = 0){}
Later you may consider to definitely remove that code and break binary compatibility. Life-cycle is better described in this Eric Lippert's SE answer (note that for simple deployments, if you do not need to keep binary compatibility, he suggest to remove code as soon as the deprecation became a compile-time error.)
Favor usage of new syntax: hide the obsolete method to minimize the chances that new users will call it instead of the new one:
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method is obsolete, use MyBetterMethod() instead.")]
public void MyMethod(int a = 0){}
Learn from this: do not use optional parameters, this is just one of the issues you will have (of course there are proper use-cases but IMO they're an exception, not the rule).
In general when writing a library you have a different approach to your public interface, be very careful about your class contract (to read as: quick fixes are an heritage you do not want to have).
When your method has too many parameters and you want to make callers' life easier then you probably have a design issue and for the rare cases where a default is really required then you should strongly consider to use an overloaded version. That said, I can't judge because I do not see your real code, there are chances that new method is doing something different or that it is doing too much.
When many parameters are unavoidable you should consider to group them all in a separate class that will be the only parameter of the method. Any time in future you can add more properties to that class and you won't break compatibility. See, for example, Process.Start()
and its ProcessStartInfo
. In this case you do not even need to rename new method:
public sealed class MyMethodInfo {
public int A { get; set; } = 0;
public int B { get; set; } = 1;
}
public void MyMethod(MyMethodInfo info) {
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method is obsolete, use MyMethod(MyMethodInfo) instead.")]
public void MyMethod(int a = 0) {
MyMethod(new MyMethodInfo { A = a });
}
One important note: default values are an important part of your interface contract, use them cum grano salis, and only when they really make sense, or force callers to specify a value. Always.