将方法分配给委托,其中委托具有比方法更多的参数

时间:2013-06-06 17:33:42

标签: c# delegates

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

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

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

3 个答案:

答案 0 :(得分:1)

这是可能的。您只需在代理中使用可选参数。

看看Jon Skeet的[回答]。

  

可选参数用于主叫方 - 而不是有效的单方法接口实现。例如,这应该编译:

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)。

答案 1 :(得分: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 :(得分:1)

基本上,你要求的是一个返回lambda的方法:

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

幸运的是,.Net包含了一种以编程方式创建lambdas的方法。这意味着您只需创建一个通用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();
}