3

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

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

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

4

3 回答 3

1

这是可能的。您所需要的只是在您的委托中使用一个可选参数。

看看乔恩斯基特的[答案]。

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

delegate void SimpleDelegate(bool x = true);

static void Main()
{
    SimpleDelegate x = Foo;
    x(); // Will print "True"
 }

 static void Foo(bool y)
 {
     Console.WriteLine(y);
 }

代表上的可选参数不能正常工作)。

于 2013-06-06T18:49:29.550 回答
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");
于 2013-06-06T18:49:42.893 回答
1

基本上,您要求的是一种返回 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();
}
于 2013-06-07T18:52:14.320 回答