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

我怎样才能用更好的解决方案来管理它?每次我都必须为每个回调创建一个委托、一个指针和一个过程。有更好的泛化方法吗?我认为每次都应该重新创建委托,但我想避免重新创建过程和指针。

首先,如果你公开 Callbackfor1Callbackfor2(我假设你的 class 成员都是 public)那么你也不需要 RegisterCallback1RegisterCallback2:它们只是使调用者代码更加冗长的辅助方法:

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 版本,您可以使用 ActionFunc 通用委托。像这样:

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 的委托并添加该参数,即使未使用也是如此)。