您在这里尝试执行的操作称为变量捕获。
在 C# 中,您可以通过定义一个内联委托来执行此操作,该委托将为您执行变量捕获:
Action<int, string> delegateWithParams = ...
Action delegateWithoutParams1 = delegate { delegateWithParams(7, "foo"); };
// or if you like lambda syntax:
Action delegateWithoutParams2 = () => delegateWithParams(7, "foo");
C++/CLI 没有内联委托或 lambda,因此您必须手动进行变量捕获。这是我编写的一个类,用于帮助捕获变量和我的测试程序。
如果你看过反编译的 C# 代码,你会发现 C# 编译器在捕获变量时基本上是在做同样的事情:它创建一个帮助类来存储捕获的变量,并且定义了不带参数的委托在该类上调用带参数的委托。
void SomeMethod(int i, String^ s)
{
Debug::WriteLine("SomeMethod was called with integer {0} and string '{1}'", i, s);
}
generic<typename T1, typename T2>
public ref class VariableCapture
{
private:
Action<T1,T2>^ delegateWithParams;
T1 item1;
T2 item2;
VariableCapture(Action<T1,T2>^ delegateWithParams, T1 item1, T2 item2)
{
this->delegateWithParams = delegateWithParams;
this->item1 = item1;
this->item2 = item2;
}
void RunDelegate()
{
this->delegateWithParams(item1, item2);
}
public:
static Action^ Capture(
Action<T1,T2>^ delegateWithParams, T1 item1, T2 item2)
{
VariableCapture<T1,T2>^ capture =
gcnew VariableCapture<T1,T2>(delegateWithParams, item1, item2);
return gcnew Action(capture, &VariableCapture<T1,T2>::RunDelegate);
}
};
int main(array<System::String ^> ^args)
{
Action<int, String^>^ delegateWithParams =
gcnew Action<int, String^>(&SomeMethod);
Action^ delegateWithoutParams =
VariableCapture<int, String^>::Capture(delegateWithParams, 7, "foo");
delegateWithoutParams();
}
输出:
使用整数 7 和字符串 'foo' 调用 SomeMethod
- 创建
delegateWithoutParams 后,您无需保留对捕获对象或带参数的委托的引用:它们将通过delegateWithoutParams 中的引用保持活动状态。
- 您需要为每个参数数量编写一个版本的 VariableCapture,以及为
Action<> 和Func<> 编写单独的版本。
- 由于这(基本上)与 C# 所做的相同,因此它的性能将与在 C# 中一样。 (没有反射开销。)