6

関数からイベントを返す構文は何ですか? (イベントを呼び出すのではなく、関数にバインドできるように返す)。

各メンバーがイベントを持つ辞書を含むコンテナー クラスがあります。

目標は、次のようなものを記述できるようにすることです。

Container c = new Container();
c.CreateEventForKey("a");             // Create the member in the dictionary
c.EventForKey("a") += some_function;  // Bind some_function to the event in the "a" member
c.OnEventForKey("a","b");             // Calls some_function with argument "b"

Container クラスは次のようになります。

public class Container {

  public class Member {
     public event Action<string> AnEvent;
     public void OnEvent( string v ) { if(AnEvent!=null) { AnEvent(v); } }
  }

  protected Dictionary<string,Member> members;

  // This seems to work OK.
  public void OnEventForKey(string k, string v) {
    if ( members.ContainsKey(k) ) { members[k].OnEvent(v); }
    else { /* report error */ }
  }

  // Can't get this to compile.
  public event Action<string> EventForKey(string k ) {
    if ( members.ContainsKey(k) ) { return members[k].AnEvent; }
    else { /* report error */ }
  }
}

EventForKeyこれが期待どおりになるように定義するにはどうすればよいですか?

4

3 に答える 3

8

関数からイベントを返す構文は何ですか?

簡単にはできません。イベント (プロパティと同様) は、実際にはファースト クラスの "オブジェクト" ではありません。彼らはクラスのメンバーです。ここには実際にはクラス メンバーはありません。デリゲートをディクショナリに保持しようとしているだけです。

独自の「イベントのような」コンテナを作成することもできますが、別のデザインを検討する方がよいでしょう。

c.Subscribe("a", SomeFunction);
c.OnEventForKey("a");

インスピレーションを得るために見たいと思うかもしれませんEventHandlerList

于 2012-04-21T07:57:14.060 に答える
2

単にメンバーに戻ってそのイベントにサブスクライブしないのはなぜですか?

public IMember MemberForKey(string key) // return IMember
{
    if (!members.ContainsKey(key))
        throw new Exception();

    return members[key];
}

そして購読します:

Container c = new Container();
c.CreateEventForKey("a");            
c.MemberForKey("a").AnEvent += some_function;
c.OnEventForKey("a", "b"); 

しかし、クラスに publicOnEventメソッドがあります。Memberクライアントによるイベントの発生を禁止するために、イベントのみを表示するインターフェイスを作成できます。このインターフェースをMemberクラスごとに実装するだけです:

public interface IMember
{
    event Action<string> AnEvent;
} 

はい、実際にはイベントはオブジェクトではなく、デリゲート型の内部フィールドにデリゲートを追加および削除するaddとの 2 つのメソッドのセットであるため、イベントを返すことはできません。removeイベントは次のようになります。

  private Action<string> _action; // field of delegate type

  public event Action<string> AnEvent
  { 
      add { _action += value; }
      remove { _action -= value; }
  }

イベントの目的は、ハンドラーの追加と削除という 2 つの操作のみをクライアントに提供することです。デリゲート自体はクライアントには表示されません。公開することができます:

public Action<string> _action;

ただし、この場合、どのクライアントもそれを呼び出すことができます。

更新: サブスクライブ/削除構文を使用する場合は、ハンドラーで辞書を使用するだけです:

public class Container
{
    private Dictionary<string, Action<string>> handlers = 
            new Dictionary<string, Action<string>>();

    public void CreateEventForKey(string key)
    {
        // with empty handler added you can avoid null check
        handlers.Add(key, (value) => { });
    }

    public void OnEventForKey(string key, string value)
    {
        if (!handlers.ContainsKey(key))
            throw new Exception();

        handlers[key](value);
    }

    public void Subscribe(string key, Action<string> handler)
    {
        if (!handlers.ContainsKey(key))
            throw new Exception();

        handlers[key] += handler;
    }
}
于 2012-04-21T08:55:42.267 に答える
0

完全な実例は次のとおりです。

class Program
{
    static void Main(string[] args)
    {
        Container c = new Container();
        c.CreateEventForKey("a");             // Create the member in the dictionary
        c.EventForKey("a").Add(str => Console.WriteLine(str));
        c.EventForKey("a").Add(str => Console.WriteLine(str.ToUpper()));
        c.OnEventForKey("a", "baa baa black sheep");

        Console.ReadLine();
        }
    }

    public class Container
    {

        public class Member
        {
        public List<Action<string>> AnEvent = new List<Action<string>>();
        public void OnEvent(string v)
        {
            if (AnEvent != null)
            {
                this.AnEvent.ForEach(action => action(v));
            }
        }

        public void AddEvent(Action<string> action)
        {
            this.AnEvent.Add(action);
        }
    }

    protected Dictionary<string, Member> members = new Dictionary<string,Member>();

    public void CreateEventForKey(string key)
    {
        this.members[key] = new Member();
    }

    // This seems to work OK.
    public void OnEventForKey(string k, string v)
    {
        if (members.ContainsKey(k)) { members[k].OnEvent(v); }
        else { /* report error */ }
    }

    public List<Action<string>> EventForKey(string k)
    {
        if (members.ContainsKey(k)) { return members[k].AnEvent; }
        else { throw new KeyNotFoundException(); }
    }
}

違いは、デリゲートのリストを使用することにより、イベントと同様に動作することです。

于 2012-04-21T08:59:21.670 に答える