2012-04-21 10 views
5

¿Cuál es la sintaxis para devolver un evento desde una función? (No para llamar al evento, devolverlo para que pueda estar vinculado a las funciones).Devolución de un evento de una función

Tengo una clase contenedor que contiene un diccionario donde cada miembro tiene un evento.

El objetivo es ser capaz de escribir algo como esto:

clase
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" 

The Container se ve así:

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 */ } 
    } 
} 

¿Cómo puedo definir EventForKey por lo que este hace lo que espero?

+1

No creo que pueda devolver un evento, pero puede devolver un delegado que pueda vincularse a un evento. ¿Es eso lo que quieres decir? –

+1

Creo que solo necesita eliminar la palabra clave de evento de su declaración de AnEvent, así como del tipo de devolución de EventForKey. –

+0

@IanNewson: la parte clave de lo que estoy teniendo problemas es 'c.EventForKey (" a ") + = some_function;'. Prefiero escribir eso que los engorrosos 'c.members [" a "]. AnEvent + = some_function', (ya que puedo agregar la comprobación de errores y el registro a la primera versión, pero no a la segunda). –

Respuesta

8

¿Cuál es la sintaxis para devolver un evento desde una función?

No puede, fácilmente. Los eventos, como las propiedades, no son realmente "objetos" de primera clase como tales; son miembros de una clase. En realidad, no tiene tiene miembro de la clase aquí; intenta mantener a los delegados en un diccionario.

podría crear su propio contenedor "similar a un evento", pero probablemente sea mejor considerar diseños alternativos, p.

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

Es posible que desee ver EventHandlerList en busca de inspiración.

0

¿Por qué no simplemente devolver el miembro y suscribirse a este evento?

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

    return members[key]; 
} 

y luego suscribirse:

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

Pero tienes método público OnEvent en Member clase. Para prohibir la generación de eventos por cliente, puede crear una interfaz que solo mostrará eventos. Sólo implementar esta interfaz por Member clase:

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

Y sí, no se puede volver caso, porque en realidad evento no se opone, se establece de dos métodos add y remove, que añaden y eliminan los delegados al ámbito interno del delegado tipo. Así es como se ve su evento:

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

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

El propósito del evento es proporcionar solo dos operaciones para los clientes: agregar y eliminar manejadores. El delegado está oculto para los clientes. Puede hacerlo público:

public Action<string> _action; 

Pero en este caso cualquier cliente puede invocarlo.

ACTUALIZACIÓN: si quieres ir con Subscribe/Quitar la sintaxis, a continuación, sólo tiene que utilizar diccionario con los manipuladores:

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

Aquí está completo ejemplo de trabajo:

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

La diferencia es que se comporten de manera similar a un evento usando una lista de delegados.

Cuestiones relacionadas