1

私は次のようなAPIを公開しようとしています

RegisterCallback<T>(Action<T> func)
{
    someObj.FuncPointer = func;
}

後で func(obj) を呼び出します .. obj はユーザーが言った型 T です。

より具体的な例:

var callbackRegistrar = new CBRegistrar();
callbackRegistrar.RegisterCallback<ISomeClass>(SomeFunc);

public static void SomeFunc(ISomeClass data)
{
    //
}

EDIT:だから私は明確ではないかもしれないので、コードを追加します:

CBRegistrar の「1 つの」オブジェクトのみを作成し、それを多くの Callbacks に接続します。

var callbackRegistrar = new CBRegistrar();
callbackRegistrar.RegisterCallback<ISomeClass>(SomeFunc);
callbackRegistrar.RegisterCallback<ISomeOtherClass>(SomeFunc2);
...

実際、上記のコードは、プラグインのディレクトリを反映して呼び出されます。

ユーザーはこれをコードに入れます -->

public static void SomeFunc(ISomeClass data)
{
    //
}

public static void SumFunc2(ISomeOtherClass data)
{
    //
}

Genericsなどを使用するとこれが不可能であるかのように見えます。私がしなければならないように見えるのは、IPluginまたは何かと呼ばれるインターフェースを作成し、ユーザーにこれを行うように依頼することです..

[PluginIdentifier(typeof(ISomeClass))]
public static void SomeFunc(IPluginData data)
{
    var castedStuff = data as ISomeClass; // ISomeClass inherits from IPluginData
}

ユーザーに処理を依頼しているように見えますが、とにかく ...

4

3 に答える 3

0

CBRegistrarは、汎用である必要があります(単一のコールバックタイプを保持しても問題がない場合)、または内部キャストを実行できます(複数のコールバックタイプを登録する必要がある場合)。

public class CBRegistrar<T>
{
    private Action<T> callback;
    private Dictionary<Type, object> callbackMap;

    public CBRegistrar()
    {
        this.callbackMap = new Dictionary<Type, object>();
    }

    public void RegisterCallback(Action<T> func)
    {
        this.callback = func;
    }

    public void RegisterGenericCallback<U>(Action<U> func)
    {
        this.callbackMap[typeof(U)] = func;
    }

    public Action<U> GetCallback<U>()
    {
        return this.callbackMap[typeof(U)] as Action<U>;
    }
}

public interface ISomeClass
{
    string GetName();
}

public class SomeClass : ISomeClass
{
    public string GetName()
    {
        return this.GetType().Name;
    }
}

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var callbackRegistrar = new CBRegistrar<ISomeClass>();

            callbackRegistrar.RegisterCallback(SomeFunc);
            callbackRegistrar.RegisterGenericCallback<ISomeClass>(SomeFunc);

            var someone = new SomeClass();

            callbackRegistrar.GetCallback<ISomeClass>()(someone);
        }

        public static void SomeFunc(ISomeClass data)
        {
            // Do something
            Console.WriteLine(data.GetName());
        }
    }
}
于 2012-05-29T05:36:04.877 に答える
0

C# ではコールバック関数はあまり使用されません。これらは、よりエレガントで操作しやすいイベントに置き換えられました。

class CBRegistrar
{
    public delegate void ActionRequiredEventHandler(object sender, ISomeClass e); 

    public event ActionRequiredEventHandler ActionRequired;
    void RaiseActionRequiredEvent(ISomeClass parm)
    {
       if ( ActionRequired != null)
       {
           ActionRequired(this, parm);
       }
    }

}

class APIConsumer
{
     var callbackRegistrar = new CBRegistrar();
     public APIConsumer()
     {

               callbackRegistrar.ActionRequired += SomeFunc;


     }
     public void SomeFunc(object sender, ISomeClass data)
     {

     }

}

それでもコールバックを使用したい場合は、多かれ少なかれ関数ポインターであるデリゲートを使用できます。

于 2012-05-29T05:21:04.577 に答える
0

それを格納するにはが必要ですAction<T> func。ここでセマンティック チェックを行う必要があります。誰かが(異なる値で) RegisterCallback 2 回呼び出した場合、コールバックを置き換えますか、それとも両方を保持しますか? 後者を想定すると、someObjおそらくevent(実際、この API 全体をイベントとして公開することができます) が必要なので、someObjクラスで:

public event Action<T> FuncPointer;
private void InvokeCallback(T data) {
    var handler = FuncPointer;
    if(handler != null) handler(data);
}

RegisterCallbackデータを保持したまま、完全に置き換えることができることに注意してくださいobj:

public event Action<T> Completed {
    add { obj.FuncPointer += value; }
    remove { obj.FuncPointer -= value; }
}

次に、使用法は次のようになります。

var callbackRegistrar = new CBRegistrar();
callbackRegistrar.Completed += SomeFunc;
于 2012-05-29T05:21:28.447 に答える