2011-01-22 41 views
22

Tôi đang trong quá trình thực hiện triển khai C# Wicket để hiểu sâu hơn về C# và Wicket. Một trong những vấn đề chúng tôi đang gặp phải là Wicket sử dụng nhiều lớp bên trong vô danh và C# không có lớp bên trong vô danh.Các lớp bên trong vô danh trong C#

Vì vậy, ví dụ, trong Wicket, bạn xác định một liên kết như thế này:

Link link = new Link("id") { 
    @Override 
    void onClick() { 
     setResponsePage(...); 
    } 
}; 

Từ Link là một lớp trừu tượng, nó buộc implementor để thực hiện một phương pháp onClick.

Tuy nhiên, trong C#, vì không có lớp bên trong vô danh, không có cách nào để thực hiện việc này. Thay vào đó, bạn có thể sử dụng các sự kiện như thế này:

var link = new Link("id"); 
link.Click += (sender, eventArgs) => setResponsePage(...); 

Tất nhiên, có một vài hạn chế với điều này. Trước hết, có thể có nhiều Trình xử lý nhấp chuột, có thể không được làm mát. Nó cũng không buộc người triển khai thêm trình xử lý Nhấp chuột.

Một lựa chọn khác có thể là để chỉ có một tài sản đóng cửa như thế này:

var link = new Link("id"); 
link.Click =() => setResponsePage(...); 

này giải quyết vấn đề của việc có nhiều bộ xử lý, nhưng vẫn không buộc các implementor thêm xử lý.

Vì vậy, câu hỏi của tôi là, làm thế nào để bạn mô phỏng một cái gì đó như thế này trong C# thành ngữ?

+1

Tôi không thấy lớp bên trong ẩn danh trong ví dụ bạn đã cung cấp. Nếu bạn muốn những người triển khai lớp trừu tượng của bạn luôn triển khai một số phương thức, bạn có thể tạo một phương thức trừu tượng trong lớp hoặc có nó thực hiện một giao diện. – tenor

+2

@tenor, có một lớp vô danh nội tuyến được định nghĩa kế thừa từ 'Liên kết' và ghi đè phương thức' onClick'. Không giống như Java, C# không hỗ trợ các lớp ẩn danh để lấy được từ một kiểu người dùng đã cho. –

+0

@ Dimitrov, cảm ơn vì đã chỉ ra điều đó. Tôi đang tìm kiếm một lớp "bên trong/lồng nhau" thực sự. Ví dụ được cung cấp trông giống như một lớp ẩn danh xuất phát từ một lớp hiện có, ít nhất là trong C# lingo. – tenor

Trả lời

17

Bạn có thể làm cho đại biểu trở thành một phần của hàm tạo của lớp Liên kết. Bằng cách này, người dùng sẽ phải thêm nó.

public class Link 
{ 
    public Link(string id, Action handleStuff) 
    { 
     ... 
    } 

} 

Sau đó, bạn tạo ra một thể hiện theo cách này:

var link = new Link("id",() => do stuff); 
+0

Vâng, điều đó sẽ hoạt động tốt với các tham số được đặt tên. – cdmckay

1

tôi bắt đầu này trước câu trả lời tốt @ meatthew của - tôi sẽ làm gần như giống hệt nhau ngoại trừ - ngoại trừ rằng tôi sẽ bắt đầu với một lớp cơ sở trừu tượng - để nếu bạn không muốn đi lộ trình thực hiện ẩn danh, bạn cũng có thể tự do thực hiện điều đó.

public abstract class LinkBase 
{ 
    public abstract string Name { get; } 
    protected abstract void OnClick(object sender, EventArgs eventArgs); 
    //... 
} 

public class Link : LinkBase 
{ 
    public Link(string name, Action<object, EventArgs> onClick) 
    { 
     _name = Name; 
     _onClick = onClick; 
    } 

    public override string Name 
    { 
     get { return _name; } 
    } 

    protected override void OnClick(object sender, EventArgs eventArgs) 
    { 
     if (_onClick != null) 
     { 
      _onClick(sender, eventArgs); 
     } 
    } 

    private readonly string _name; 
    private readonly Action<object, EventArgs> _onClick; 

} 
3

Đây là những gì tôi sẽ làm:

Giữ liên kết như một lớp trừu tượng, sử dụng một máy để nhanh chóng nó và vượt qua trong việc đóng cửa của bạn/phương pháp vô danh như một tham số cho phương pháp xây dựng của Nhà máy. Bằng cách này, bạn có thể giữ thiết kế ban đầu của mình với Liên kết dưới dạng lớp trừu tượng, buộc triển khai thông qua nhà máy và vẫn ẩn bất kỳ dấu vết cụ thể nào của Liên kết bên trong nhà máy.

Dưới đây là một số mã ví dụ:

class Program 
{ 
    static void Main(string[] args) 
    { 

     Link link = LinkFactory.GetLink("id",() => 
     // This would be your onClick method. 
     { 
       // SetResponsePage(...); 
       Console.WriteLine("Clicked"); 
       Console.ReadLine(); 
     }); 
     link.FireOnClick(); 
    } 
    public static class LinkFactory 
    { 
     private class DerivedLink : Link 
     { 
      internal DerivedLink(String id, Action action) 
      { 
       this.ID = id; 
       this.OnClick = action; 
      } 
     } 
     public static Link GetLink(String id, Action onClick) 
     { 
       return new DerivedLink(id, onClick); 
     } 
    } 
    public abstract class Link 
    { 
     public void FireOnClick() 
     { 
      OnClick(); 
     } 
     public String ID 
     { 
      get; 
      set; 
     } 
     public Action OnClick 
     { 
      get; 
      set; 
     } 
    } 
} 

EDIT: Trên thực tế, Đây có thể là một chút gần gũi hơn với những gì bạn muốn:

Link link = new Link.Builder 
{ 
    OnClick =() => 
    { 
     // SetResponsePage(...); 
    }, 
    OnFoo =() => 
    { 
     // Foo! 
    } 
}.Build("id"); 

Vẻ đẹp là nó sử dụng một khối init, cho phép bạn khai báo nhiều triển khai tùy chọn của các hành động trong lớp Liên kết như bạn muốn.

Đây là lớp Liên kết có liên quan (Với lớp bên trong Trình tạo kín).

public class Link 
{ 
    public sealed class Builder 
    { 
     public Action OnClick; 
     public Action OnFoo; 
     public Link Build(String ID) 
     { 
      Link link = new Link(ID); 
      link.OnClick = this.OnClick; 
      link.OnFoo = this.OnFoo; 
      return link; 
     } 
    } 
    public Action OnClick; 
    public Action OnFoo; 
    public String ID 
    { 
     get; 
     set; 
    } 
    private Link(String ID) 
    { 
     this.ID = ID; 
    } 
} 

Điều này gần với những gì bạn đang tìm kiếm, nhưng tôi nghĩ chúng tôi có thể tiến thêm một bước với các đối số được đặt tên tùy chọn, tính năng C# 4.0. Hãy xem tuyên bố ví dụ về Liên kết với các đối số được đặt tên tùy chọn:

Link link = Link.Builder.Build("id", 
    OnClick:() => 
    { 
     // SetResponsePage(...); 
     Console.WriteLine("Click!"); 
    }, 
    OnFoo:() => 
    { 
     Console.WriteLine("Foo!"); 
     Console.ReadLine(); 
    } 
); 

Tại sao điều này thú vị? Chúng ta hãy nhìn vào các lớp liên kết mới:

public class Link 
{ 
    public static class Builder 
    { 
     private static Action DefaultAction =() => Console.WriteLine("Action not set."); 
     public static Link Build(String ID, Action OnClick = null, Action OnFoo = null, Action OnBar = null) 
     { 
      return new Link(ID, OnClick == null ? DefaultAction : OnClick, OnFoo == null ? DefaultAction : OnFoo, OnBar == null ? DefaultAction : OnBar); 
     } 
    } 
    public Action OnClick; 
    public Action OnFoo; 
    public Action OnBar; 
    public String ID 
    { 
     get; 
     set; 
    } 
    private Link(String ID, Action Click, Action Foo, Action Bar) 
    { 
     this.ID = ID; 
     this.OnClick = Click; 
     this.OnFoo = Foo; 
     this.OnBar = Bar; 
    } 
} 

Bên trong lớp Builder tĩnh, có một phương pháp nhà máy xây dựng mà mất trong 1 thông số cần thiết (ID) và 3 thông số tùy chọn, OnClick, OnFoo và OnBar. Nếu chúng không được chỉ định, phương thức factory sẽ cho chúng thực hiện mặc định.

Vì vậy, trong các đối số tham số của hàm tạo cho Liên kết, bạn chỉ cần thực hiện các phương thức mà bạn cần, nếu không chúng sẽ sử dụng hành động mặc định, không thể là gì.

Hạn chế, tuy nhiên, là trong ví dụ cuối cùng, lớp Liên kết không trừu tượng. Nhưng nó không thể được khởi tạo bên ngoài phạm vi của lớp Link, bởi vì hàm tạo của nó là private (Bắt buộc sử dụng lớp Builder để khởi tạo liên kết).

Bạn cũng có thể di chuyển các tham số tùy chọn vào trong hàm tạo của Link trực tiếp, tránh sự cần thiết cho một nhà máy hoàn toàn.

+0

Đây là câu trả lời là từ 3 năm trước, nhưng tôi chỉ nghĩ rằng tôi muốn đề cập đến trong câu trả lời cuối cùng của bạn, bạn có thể rút ngắn dòng trả lại một chút: trả về liên kết mới (ID, OnClick ?? DefaultAction, OnFoo ?? DefaultAction, OnBar ?? DefaultAction); –

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