【问题标题】:Parameter Action<T1, T2, T3> in which T3 can be optional参数 Action<T1, T2, T3> 其中 T3 可以是可选的
【发布时间】:2011-12-03 04:17:46
【问题描述】:

我有以下代码:

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

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

注意可选的 param3 参数。

现在由于很多原因,我需要将 MyMethod 方法的代码提取到它自己的类中,但我不能用它提取 ProtectedMethod,因为所有类都继承自这个类,我需要保持较小的更改并且孤立。所以我想我可以在新类中有一个 Action 委托,其签名与 ProtectedMethod 相同。

问题是,如果我这样声明委托:

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

提取的代码不喜欢它,因为它说该方法仅使用两个参数调用。

如果我这样声明委托:

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

当我将它作为参数发送给新类时,它也不喜欢它,因为该方法被定义为具有三个参数而不是两个。

到目前为止,我想到的解决此问题的唯一方法是创建 ProtectedMethod 的重载版本以消除可选参数。

这是唯一的选择还是有另一种方法,因为现在首选的选择是使用可选参数而不是重载方法?

【问题讨论】:

标签: c# oop delegates optional-parameters


【解决方案1】:

可选参数是方法或委托参数的属性。当您在编译时调用具有已知可选参数的签名(方法或委托)时,编译器将在调用点插入可选参数值。

运行时不知道可选参数,因此您不能创建一个在调用时插入可选参数的委托。

相反,您需要使用可选参数声明自定义委托类型:

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

调用此委托时,您可以省略第三个参数,而不管它包含的方法的声明。

【讨论】:

  • 类型参数可以是可选的吗?
  • @JoelCoehoorn - 否 - 泛型创建新类型
  • 似乎它们并不比属性更强大。可能仍然有用:)
  • @leppie:可选参数是属性。 blog.slaks.net/2011/01/optional-parameters-in-c-4.html
  • @SLaks 非常感谢,这使得解决方案得以编译。遗憾的是,使用通用 Action 您可以立即看到该方法必须具有的签名是什么,而使用委托您只能在智能感知上看到 MyMethod(MyDelegate myDelegate)。哦,好吧,我想您有时无法全部了解。
【解决方案2】:

这取决于m_ProtectedMethod 的使用方式,但我在自己的情况下找到了一种折衷方案,即我使用一个重载比另一个多。

只需定义一个更简单(具有较少通用参数)的 Action 变量,它调用更复杂的提供的 Action 变量方法。这可以在 (i) 本地使用范围内完成;或 (ii) 分配 Action 属性或对象构造时的对象范围。

因为不存在变量/属性重载之类的东西,所以您需要两个不同的名称,用于生成两个相关的 Action 变量。

EG i:本地范围(可能不是最适合您的场景)

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:对象范围

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  
}

请注意,在这两种情况下,我都将默认设置值设计为命名更笨拙的变量,具有 2 后缀,这样在使用时,更简单的重载具有更基本的变量名称。

【讨论】:

    【解决方案3】:

    希望通过我发现的更优雅的重载实现与(面向委托的)策略模式相结合来帮助其他人。

    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);
        }
    }
    

    用法:

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

    【讨论】:

      猜你喜欢
      • 2020-01-09
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 1970-01-01
      相关资源
      最近更新 更多