我面临着一个不使用 .NET 事件的遗留 API,而是要求我这样做:
// (first arg is System.Object, second arg is string, myFoo is of type Foo)
myFoo.AddCallback(this, "DoSomething(int)");
此 API 要求 DoSomething
是 this
上的实例方法,并且它需要一个 int。
有没有办法可以强制此 API 以类型安全的方式使用?
更准确地说:我想为 Foo 编写一个扩展方法,它允许我使用 .NET 委托(delegate)(而不是接收者签名对)调用 AddCallback。我正在想象这样的事情:
// extension method definition
public static void AddCallback(this Foo foo, Action action)
{
foo.AddCallback(
FigureOutReceiverOf(action), // ?
FigureOutSignatureOf(action)); // ?
}
public static void AddCallback<T>(this Foo foo, Action<T> action)
{ ... } // and so on, for up to, say, 10 type-arguments
// usage:
myFoo.AddCallback(DoSomething)
// or even a lambda:
myFoo.AddCallback((i) => Console.WriteLine(i));
如果可以通过扩展方法 hack 来做到这一点,那会让我的生活变得更好。另外,我只是感兴趣是否可以考虑到 C# 的功能。
顺便说一下,旧版 API 称为 qt4dotnet。
最佳答案
使用 lambda 会很棘手 - 如果它捕获局部变量,它最终将成为不同类中的方法。当然,您可以检测到这一点,但编译时并不安全。
同样,签名部分很有趣,因为如果它绝对是一个操作
,则委托(delegate)没有参数。您不能只让参数Delegate
,否则方法组转换将不起作用...尽管您仍然可以调用
myFoo.AddCallBack(new Action<int>(MyMethodName));
另一种方法是产生一堆重载:
public static void AddCallback(this Foo foo, Action action)
public static void AddCallback<T>(this Foo foo, Action<T> action)
public static void AddCallback<T1, T2>(this Foo foo, Action<T1, T2> action)
这并不优雅,但出于实际原因您可能只需要一些。如果有任何方法返回值,您需要为 Func
提供类似的值。
传递具有多个操作的委托(delegate)还有一个额外的潜在问题...同样,您可以在编译时检查这一点。最后,您可能需要检查委托(delegate)的 Target
是否与 foo
参数相同。
解决了这些问题后,计算签名就变得相对简单了。您可以使用 Delegate.Method
属性,从中您可以获取名称和参数类型。如果库需要 "int"
而不是 "System.Int32"
等,那么您将需要对此进行一些处理,但这应该不会太糟糕。 (不过,这听起来确实是一个相当奇怪的 API。)
关于c# - 旧版 API 需要将回调名称作为字符串传递。我可以通过扩展方法改进该 API 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3732939/