将方法分配给委托,其中委托具有比方法更多的参数
本文关键字:方法 参数 分配 | 更新日期: 2023-09-27 18:17:27
我有一个委托,它有很多参数,像这样:
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");
};
但这只适用于不带参数的内联方法。如果我想像第二个例子那样使用其中一个参数,我就需要拥有所有的参数。
你总是可以用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");
这是可能的。你只需要在委托中使用一个可选参数。
看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);
}
(委托的可选参数不能正常工作)。
基本上,你所要求的是一个方法,返回一个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();
}