从函数返回事件

本文关键字:事件 返回 函数 | 更新日期: 2023-09-27 18:32:00

从函数返回事件的语法是什么?(不调用事件,返回它以便它可以绑定到函数)。

我有一个容器类,其中包含一个字典,其中每个成员都有一个事件。

目的是能够写出这样的东西:

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"

容器类如下所示:

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以便它达到我的期望?

从函数返回事件

从函数返回事件的语法是什么?

你不能,很容易。事件(如属性)本身并不是真正的第一类"对象";他们是班级的成员。你在这里并没有真正的类成员 - 你只是试图将委托保留在字典中。

您可以创建自己的"类似事件"的容器,但最好考虑其他设计,例如

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

您可能想从EventHandlerList中寻找灵感。

为什么不简单地返回成员并订阅它的事件?

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

但是您在Member类中有公共OnEvent方法。为了禁止客户端引发事件,您可以创建仅显示事件的界面。只需通过Member类实现此接口:

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

是的,你不能返回事件,因为实际上事件不是对象,它是一组addremove两个方法,它们在委托类型的内部字段中添加和删除委托。以下是您的活动的外观:

  private Action<string> _action; // field of delegate type
  public event Action<string> AnEvent
  { 
      add { _action += value; }
      remove { _action -= value; }
  }

事件的目的是仅为客户端提供两个操作 - 添加和删除处理程序。委托本身对客户端是隐藏的。您可以将其公开:

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

这是完整的工作示例:

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

区别在于通过使用委托列表来使行为类似于事件。