【问题标题】:Assigning a method to a delegate where the delegate has more parameters than the method [duplicate]将方法分配给委托,其中委托的参数多于方法[重复]
【发布时间】:2013-06-06 17:33:42
【问题描述】:

我有一个接受很多参数的委托,如下所示:

public delegate void MyDelegate(float thereAre, int lotsOf, string parametersIn, int thisDelegate);
public MyDelegate theDelegateInstance;

这很烦人,因为 Visual Studio 2010 没有任何类型的自动完成功能来帮助方法匹配委托签名。我基本上希望能够编写一个方法,该方法只接受委托的一些(或不接受)参数,而忽略其他参数,因为它无论如何都不使用它们。

theDelegateInstance += delegate()
{
    Debug.Log("theDelegateInstance was called");
};

或者

theDelegateInstance += delegate(float thereAre, int lotsOf)
{
    if(thereAre > lotsOf) Debug.Log("thereAre is way too high");
};

我发现我可以让一个方法接受一个委托,返回一个 MyDelegate,像这样调用它:

public delegate void VoidMethod();

public static MyDelegate ConvertToMyDelegate(VoidMethod method)
{
    return delegate(float thereAre, int lotsOf, string parametersIn, int thisDelegate)
    {
        method();
    };
}

但这需要我为每个不同的转换声明一个静态方法。

我刚刚发现我可以在没有任何参数的情况下执行我的第一个示例来达到预期的结果:

theDelegateInstance += delegate//Notice that there are no brackets here.
{
    Debug.Log("theDelegateInstance was called");
};

但这仅适用于不带参数的内联方法。如果我想像第二个例子那样使用其中一个参数,我需要拥有所有这些参数。

【问题讨论】:

    标签: c# delegates


    【解决方案1】:

    你总是可以用 lambdas 做到这一点。

    您可以通过两种方式进行 - 使用您要调用的两个示例函数:

    第一种方式——创建方法,直接调用:

    void FirstFunction(float thereAre, int lotsOf)
    {
        if(thereAre > lotsOf) 
            Debug.Log("thereAre is way too high");
    }
    

    并以这种方式调用它:

    theDelegateInstance += (t, l, p, td) => FirstFunction(t, l);
    

    第二种方式——直接调用而不创建函数:

    theDelegateInstance += 
        (t, l, p, td) => Debug.Log("theDelegateInstance was called");
    

    【讨论】:

      【解决方案2】:

      这是可能的。您只需在委托中使用可选参数即可。

      看看 Jon Skeet 的 [answer]。

      可选参数用于调用端 - 而不是像单方法接口实现那样有效。例如,这应该编译:

      delegate void SimpleDelegate(bool x = true);
      
      static void Main()
      {
          SimpleDelegate x = Foo;
          x(); // Will print "True"
       }
      
       static void Foo(bool y)
       {
           Console.WriteLine(y);
       }
      

      (Optional parameters on delegates doesn't work properly).

      【讨论】:

      • 请在您的答案中包含一个示例(如果您愿意,还可以添加一个链接),而不是让您的答案依赖于链接。
      【解决方案3】:

      基本上,您要求的是一个返回 lambda 的方法,如下所示:

      public static MyDelegate ConvertToMyDelegate(VoidMethod method)
      {
          return (thereAre, lotsOf, parametersIn, thisDelegate) => method();
      }
      

      幸运的是,.Net 包含一种以编程方式创建 lambda 的方法。这意味着您可以只创建一个通用的Convert 方法,它可以处理两种委托类型中的任意数量的参数:

      public static TTarget ConvertDelegate<TSource, TTarget>(TSource sourceDelegate)
      {
          if (!typeof(Delegate).IsAssignableFrom(typeof(TSource)))
              throw new InvalidOperationException("TSource must be a delegate.");
          if (!typeof(Delegate).IsAssignableFrom(typeof(TTarget)))
              throw new InvalidOperationException("TTarget must be a delegate.");
          if (sourceDelegate == null)
              throw new ArgumentNullException("sourceDelegate");
      
          var parameterExpressions = typeof(TTarget)
              .GetMethod("Invoke")
              .GetParameters()
              .Select(p => Expression.Parameter(p.ParameterType))
              .ToArray();
      
          var sourceParametersCount = typeof(TSource)
              .GetMethod("Invoke")
              .GetParameters()
              .Length;
      
          var expression = Expression.Lambda<TTarget>(
              Expression.Invoke(
                  Expression.Constant(sourceDelegate),
                  parameterExpressions.Take(sourceParametersCount)),
              parameterExpressions);
      
          return expression.Compile();
      }
      

      【讨论】:

      • +1,这太棒了..
      猜你喜欢
      • 2015-04-22
      • 2022-01-06
      • 2013-12-25
      • 2023-04-10
      • 2016-11-10
      • 1970-01-01
      • 1970-01-01
      • 2015-12-17
      相关资源
      最近更新 更多