C ++概括代表

时间:2015-06-11 07:55:10

标签: .net callback delegates c++-cli

我有一个类似的情况:

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

我如何在更好的解决方案中管理它?我每次都必须为每个Callback创建一个委托,一个指针和一个过程。有一种更好的推广方法吗?我认为每次都应重新创建委托,但我想避免重新创建过程和指针。

1 个答案:

答案 0 :(得分:1)

首先,如果您公开Callbackfor1Callbackfor2(我假设您的班级成员都是公开的)那么您还不需要RegisterCallback1RegisterCallback2:他们'只是帮助方法,使调用者代码更加冗长:

manager->RegisterCallback1(YourMethod);

而不是:

manager->Callbackfor1 += YourMethod;

但请注意,让你的代表公开你完全暴露他们,来电者可以写下:

manager->Answer1 = nullptr;

然后在我看来你应该删除那些辅助方法(保持你的字段公开)或保持辅助方法(使字段为私有)。还有另一种选择:事件。它们完全是委托,但不允许调用者设置它们(仅在调用列表中添加/删除函数):

ref class Manager {
public:
    event answer1^ Callback1;
};

请注意,使它们成为事件(或将它们保密)也会阻止调用者直接调用它们,您只能从您声明它们的类中引发事件。谁使用你的班级:

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事件模式中再迈一步。让我们创建两个类(我不知道你的域名,所以我选择随机名称):

ref class Callback1EventArgs sealed : EventArgs {
public:
    Callback1EventArgs(String^ message, int value) {
        Message = message;
        Value = value;
    }

    property String^ Message;
    property int Value;
};

现在更改您的Manager课程:

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类中,您将引发这样的事件(无需检查nullptr并使其成为线程安全的,C ++ / CLI会为您生成正确的代码,请注意这一点因为event关键字而不管委托签名而发生。这段代码:

answer1^ callbackfor1 = Callbackfor1;
if (callbackfor1 != nullptr)
    callbackfor1(L"Some message", 0);

将成为:

Callback1(this, gcnew Callback1EventArgs(L"Some message", 0));

这样更好吗?好吧有一个类会使你的代码更加冗长但是当参数改变时它会有很多帮助:你只需要添加一个属性并重新编译(使用方法参数,你需要找到并更新注册为{{{}的委托的每个方法。 1}}并添加该参数,即使未使用)。