C++ 泛化委托
C++ Generalize delegates
我也有类似情况:
ref class Manager
{
delegate void answer1(String^ Message, int Avalue);
delegate void answer2(Object^ Obj, double Something);
answer1 ^ Callbackfor1;
answer2 ^ Callbackfor2;
void RegisterCallback1(answer1 ^ Address);
void RegisterCallback2(answer2 ^ Address);
}
我怎样才能用更好的解决方案来管理它?每次我都必须为每个回调创建一个委托、一个指针和一个过程。有更好的泛化方法吗?我认为每次都应该重新创建委托,但我想避免重新创建过程和指针。
首先,如果你公开 Callbackfor1
和 Callbackfor2
(我假设你的 class 成员都是 public)那么你也不需要 RegisterCallback1
和 RegisterCallback2
:它们只是使调用者代码更加冗长的辅助方法:
manager->RegisterCallback1(YourMethod);
而不是:
manager->Callbackfor1 += YourMethod;
但是请注意,让您的代表 public 您完全暴露了他们,来电者可以这样写:
manager->Answer1 = nullptr;
那么在我看来,您应该删除该辅助方法(保留您的字段 public)或保留辅助方法(将字段设为私有)。还有另一种选择:事件。它们完全是委托,但不允许调用者设置它们(调用列表中只有 add/remove 个函数):
ref class Manager {
public:
event answer1^ Callback1;
};
请注意,将它们设为事件(或将它们设为私有)也会阻止调用者直接调用它们,您只能在声明它们的 class 中引发事件)。谁在使用你的class:
manager->Callback1 += YourMethod; // Add to invocation list
manager->Callback1 -= YourMethod; // Remove from invocation list
manager->Callback1 = nullptr; // Not allowed: it doesn't compile
manager->Callback1(L"some text", 0); // Not allowed: it doesn't compile
关于委托声明和签名:如果您的目标是新的 .NET Framework 版本,您可以使用 Action
和 Func
通用委托。像这样:
ref class Manager {
public:
event Action<String^, int>^ Callback1;
event Action<Object^, double>^ Callback2;
};
就是这样。请注意,如果您改为将这些委托不可用的 .NET Framework 2.0 作为目标,那么您可以编写一次并重新使用它们:
generic <class T1, class T2>
public delegate Action(T1 t1, T2 t2);
并如前所述使用它们。让我们进一步了解 common .NET 事件模式。让我们创建两个 classes(我不知道你的域所以我随机选择名称):
ref class Callback1EventArgs sealed : EventArgs {
public:
Callback1EventArgs(String^ message, int value) {
Message = message;
Value = value;
}
property String^ Message;
property int Value;
};
现在改变你的 Manager
class:
ref class Manager {
public:
event EventHandler<Callback1EventArgs^>^ Callback1;
};
用法相同:
manager->Callback1 += YourMethod;
但方法签名不同:
void YourMethod(Object^ sender, Callback1EventArgs^ e) {
// In case you need it you have a reference to object
// that generated this "event".
Manager^ manager = safe_cast<Manager^>(sender);
// You find all your properties inside event arguments
Console::WriteLine(L"Message is {0} and value is {1}",
e->Message, e->Value);
}
在您的 Manager
class 中,您将引发这样的事件(无需检查 nullptr
并使其线程安全,C++/CLI 生成正确的代码对你来说,请注意这是因为 event
关键字而不管委托签名)。此代码:
answer1^ callbackfor1 = Callbackfor1;
if (callbackfor1 != nullptr)
callbackfor1(L"Some message", 0);
将成为:
Callback1(this, gcnew Callback1EventArgs(L"Some message", 0));
这样更好吗?好吧,有一个 class 会让你的代码更冗长一点,但是当参数改变时它会有很大帮助:你只需要添加一个 属性 并重新编译(使用你需要查找和更新的方法参数每个方法都注册为 Callback1
的委托并添加该参数,即使未使用也是如此)。
我也有类似情况:
ref class Manager
{
delegate void answer1(String^ Message, int Avalue);
delegate void answer2(Object^ Obj, double Something);
answer1 ^ Callbackfor1;
answer2 ^ Callbackfor2;
void RegisterCallback1(answer1 ^ Address);
void RegisterCallback2(answer2 ^ Address);
}
我怎样才能用更好的解决方案来管理它?每次我都必须为每个回调创建一个委托、一个指针和一个过程。有更好的泛化方法吗?我认为每次都应该重新创建委托,但我想避免重新创建过程和指针。
首先,如果你公开 Callbackfor1
和 Callbackfor2
(我假设你的 class 成员都是 public)那么你也不需要 RegisterCallback1
和 RegisterCallback2
:它们只是使调用者代码更加冗长的辅助方法:
manager->RegisterCallback1(YourMethod);
而不是:
manager->Callbackfor1 += YourMethod;
但是请注意,让您的代表 public 您完全暴露了他们,来电者可以这样写:
manager->Answer1 = nullptr;
那么在我看来,您应该删除该辅助方法(保留您的字段 public)或保留辅助方法(将字段设为私有)。还有另一种选择:事件。它们完全是委托,但不允许调用者设置它们(调用列表中只有 add/remove 个函数):
ref class Manager {
public:
event answer1^ Callback1;
};
请注意,将它们设为事件(或将它们设为私有)也会阻止调用者直接调用它们,您只能在声明它们的 class 中引发事件)。谁在使用你的class:
manager->Callback1 += YourMethod; // Add to invocation list
manager->Callback1 -= YourMethod; // Remove from invocation list
manager->Callback1 = nullptr; // Not allowed: it doesn't compile
manager->Callback1(L"some text", 0); // Not allowed: it doesn't compile
关于委托声明和签名:如果您的目标是新的 .NET Framework 版本,您可以使用 Action
和 Func
通用委托。像这样:
ref class Manager {
public:
event Action<String^, int>^ Callback1;
event Action<Object^, double>^ Callback2;
};
就是这样。请注意,如果您改为将这些委托不可用的 .NET Framework 2.0 作为目标,那么您可以编写一次并重新使用它们:
generic <class T1, class T2>
public delegate Action(T1 t1, T2 t2);
并如前所述使用它们。让我们进一步了解 common .NET 事件模式。让我们创建两个 classes(我不知道你的域所以我随机选择名称):
ref class Callback1EventArgs sealed : EventArgs {
public:
Callback1EventArgs(String^ message, int value) {
Message = message;
Value = value;
}
property String^ Message;
property int Value;
};
现在改变你的 Manager
class:
ref class Manager {
public:
event EventHandler<Callback1EventArgs^>^ Callback1;
};
用法相同:
manager->Callback1 += YourMethod;
但方法签名不同:
void YourMethod(Object^ sender, Callback1EventArgs^ e) {
// In case you need it you have a reference to object
// that generated this "event".
Manager^ manager = safe_cast<Manager^>(sender);
// You find all your properties inside event arguments
Console::WriteLine(L"Message is {0} and value is {1}",
e->Message, e->Value);
}
在您的 Manager
class 中,您将引发这样的事件(无需检查 nullptr
并使其线程安全,C++/CLI 生成正确的代码对你来说,请注意这是因为 event
关键字而不管委托签名)。此代码:
answer1^ callbackfor1 = Callbackfor1;
if (callbackfor1 != nullptr)
callbackfor1(L"Some message", 0);
将成为:
Callback1(this, gcnew Callback1EventArgs(L"Some message", 0));
这样更好吗?好吧,有一个 class 会让你的代码更冗长一点,但是当参数改变时它会有很大帮助:你只需要添加一个 属性 并重新编译(使用你需要查找和更新的方法参数每个方法都注册为 Callback1
的委托并添加该参数,即使未使用也是如此)。