2012-04-21 44 views
5

Cú pháp trả về một sự kiện từ một hàm là gì? (Không gọi sự kiện này, để trả lại nó để nó có thể bị ràng buộc với các chức năng).Trả về một sự kiện từ một hàm

Tôi có một lớp chứa chứa từ điển mà mỗi thành viên có một sự kiện.

Mục đích là để có thể viết một cái gì đó như thế này:

lớp
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" 

Các container trông như thế này:

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

Làm thế nào tôi có thể xác định EventForKey để điều này làm những gì tôi mong đợi?

+1

Tôi không nghĩ bạn có thể trả lại sự kiện, nhưng bạn có thể trả lại một đại biểu có thể bị ràng buộc vào một sự kiện. Đó có phải là ý bạn không? –

+1

Tôi nghĩ bạn chỉ cần loại bỏ từ khóa sự kiện khỏi khai báo AnEvent của bạn, cũng như từ kiểu trả về của EventForKey. –

+0

@IanNewson - phần quan trọng của những gì tôi đang gặp phải là 'c.EventForKey (" a ") + = some_function;'. Tôi muốn viết nó hơn là cồng kềnh 'c.members [" a "]. AnEvent + = some_function', (như tôi có thể thêm lỗi kiểm tra và đăng nhập vào phiên bản đầu tiên, nhưng không phải để lần thứ hai). –

Trả lời

8

Cú pháp trả về sự kiện từ một hàm là gì?

Bạn không thể, dễ dàng. Sự kiện - như các thuộc tính - không thực sự là "đối tượng" lớp đầu tiên như vậy; họ là thành viên của một lớp học. Bạn không thực sự thành viên lớp học ở đây - bạn đang cố gắng chỉ giữ đại biểu trong từ điển.

Bạn có thể tạo vùng chứa "giống như sự kiện" của riêng bạn, nhưng tốt hơn hết là nên xem xét các thiết kế thay thế, ví dụ:

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

Bạn có thể muốn xem EventHandlerList để lấy cảm hứng.

0

Tại sao không chỉ trả lại thành viên và đăng ký sự kiện của nó?

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

    return members[key]; 
} 

Và sau đó đăng ký:

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

Nhưng bạn phải OnEvent phương pháp nào trong Member lớp. Để cấm các sự kiện nâng cao của khách hàng, bạn có thể tạo giao diện chỉ hiển thị sự kiện. Chỉ cần cài đặt giao diện này bằng cách Member lớp:

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

Và vâng, bạn không thể quay trở lại sự kiện, bởi vì thực sự kiện này được không phản đối, nó được thiết lập của hai phương pháp addremove, mà thêm và loại bỏ các đại biểu đến lĩnh vực bên trong của đại biểu kiểu. Đây là cách sự kiện của bạn trông giống như:

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

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

Mục đích của sự kiện là chỉ cung cấp hai hoạt động cho khách hàng - thêm và xóa trình xử lý. Đại biểu chính nó được ẩn cho khách hàng. Bạn có thể công khai công khai:

public Action<string> _action; 

Nhưng trong trường hợp này, bất kỳ ứng dụng khách nào đều có thể gọi.

UPDATE: nếu bạn muốn đi với Theo dõi/Remove cú pháp, sau đó chỉ cần sử dụng từ điển với bộ xử lý:

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

Dưới đây là hoàn toàn ví dụ làm việc:

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

Sự khác biệt là cư xử tương tự một sự kiện bằng cách sử dụng danh sách đại biểu.

Các vấn đề liên quan