开发者

Parameter Action<T1, T2, T3> in which T3 can be optional

I have the following code:

public static MyMethod()  
{ 
   ...Do something  
   ProtectedMethod(param1, param2);  
   ...Do something  
}  

protected static void ProtectedMethod(IEnumerable<string> param1, string param2, int param3 = 1)  
{  
   ... Do something  
}

Take notice of the optional param3 parameter.

Now for quite a few reasons I need to extract the code of the MyMethod method into its own class but I cannot extract ProtectedMethod with it because of all the classes that are inheriting from this one and I need to keep the changes small and isolated. So I figured I could have an Action<> delegate in the new class with the same signature as ProtectedMethod.

The problem is that if I declare the delegate like this:

protected readonly Action<IEnumerable<string>, string, int> m_ProtectedMethod;

The extracted code does not like it because it says the method is only being invoked with two parameters.

And if I declare the delegate like so:

protected readonly Action<IEnumerable<string>, string> m_ProtectedMethod;

When I send it as a parameter to the new class it does not like it either because the method is defined as having three parameters not two.

So far the only way I have thought of to solve this is to create an overloaded version of ProtectedMethod to eliminate the optional parameter.

Is this the only option or is there another w开发者_如何学编程ay of doing it since now the preferred choice is to have optional parameters instead of overloaded methods?


Optional parameters are an attribute of a method or delegate parameter. When you call a signature (method or delegate) that has a known optional parameter at compile-time, the compiler will insert the optional parameter value at the callsite.

The runtime is not aware of optional parameters, so you can't make a delegate that inserts an optional parameter when it's called.

Instead, you need to declare a custom delegate type with an optional parameter:

public delegate void MyDelegate(IEnumerable<string> param1, string param2, int param3 = 1);

When calling this delegate, you will be able to omit the third parameter, regardless of the declaration of the method(s) it contains.


It would depend on how m_ProtectedMethod would be consumed, but I found a compromise in my own situation, where I use one overload more than the other.

Simply define a simpler (having less generic parameters) Action<> variable, which calls the more complex supplied Action variable method. This can be accomplished either in (i) local scope on use; or (ii) object scope upon assignment of Action property or object construction.

Because there is no such thing as variable/property overloading, you need two different names, for the resulting two related Action variables.

EG i: Local Scope (probably not the most suitable for your scenario)

public MyMethod(Action<IEnumerable<string>, string, int> m_ProtectedMethod2)  
{ 
   Action<IEnumerable<string>, string> m_ProtectedMethod = (p1,p2) => {
      m_ProtectedMethod2(p1,p2,1); //The value 1 is the default 3rd parameter
   }

   ...Do something  
   m_ProtectedMethod(param1, param2);  
   ...Do something  
   ...If something  
      m_ProtectedMethod2(param1, param2, param3); //Calling the more complex form directly
   ...Do something  
}  

EG ii: Object Scope

private Action<IEnumerable<string>, string, int> m_ProtectedMethod2 = null;
private Action<IEnumerable<string>, string> m_ProtectedMethod = null;
protected Action<IEnumerable<string>, string, int> ProtectedMethod
{
   get { return m_ProtectedMethod2; }
   set {
      m_ProtectedMethod2 = value;
      m_ProtectedMethod = (p1,p2) => {
         m_ProtectedMethod2(p1,p2,1); //The value 1 is the default 3rd parameter
      }
   }
}

public MyMethod()
{
   ...Do something  
   m_ProtectedMethod(param1, param2);  
   ...Do something  
   ...If something  
      m_ProtectedMethod2(param1, param2, param3); //Calling the more complex form directly
   ...Do something  
}

Note in both cases I designed the default setting value to be the more awkwardly named variable, having the 2 suffix, such that upon consumption the simpler overload has the more basic variable name.


Hoping to help others with what I find as being a more elegant implementation of overloading mixed with the (delegate-oriented) strategy pattern.

public class OverloadExample {
    private Action<int, bool> _implementation;

    public OverloadExample() {
        _implementation = defaultImplementation;
    }

    public OverloadExample(Action<int, bool> implementation) {
        _implementation = implementation;
    }

    protected void defaultImplementation(int aInt, bool aBool) {
        //
    }

    public void Implementation(int someInt, bool someBool = true) {
        _implementation(someInt, someBool);
    }
}

Usage:

new OverloadExample().Implementation(9001);
new OverloadExample().Implementation(9001, false);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜