2013-01-09 13 views
6

Język programowania Dart ma obsługę method cascades. kaskady metoda pozwoliłaby następujące Silverlight/WPF C#:Symulacja kaskad metod w języku C#

var listBox = new ListBox(); 

listBox.Width = 200; 
listBox.MouseEnter += (s, e) => Console.WriteLine("MouseEnter"); 

var button1 = new Button() { Content = "abc" }; 
button1.Click += (s, e) => Console.WriteLine("button1.Click"); 

listBox.Items.Add(button1); 

var button2 = new Button() { Content = "def" }; 
button2.Click += (s, e) => Console.WriteLine("button2.Click"); 

listBox.Items.Add(button2); 

ContentPanel.Children.Add(listBox); 

być napisane zamiast jak:

ContentPanel.Children.Add(
    new ListBox() 
     ..Width = 200 
     ..MouseEnter += ((s, e) => Console.WriteLine("MouseEnter")) 
     ..Items.Add(
      new Button() 
       ..Content = "abc"; 
       ..Click += ((s, e) => Console.WriteLine("button 1 Click"))) 
     ..Items.Add(
      new Button() 
       ..Content = "def"; 
       ..Click += (s, e) => (Console.WriteLine("button 2 Click")))); 

Moje pytanie brzmi, czy istnieje sposób, aby symulować lub metoda ściśle przybliżone kaskady w C#?

Oto jedno podejście, które wymyśliłem. Biorąc pod uwagę tę metodę rozszerzenia:

public static T Call<T>(this T obj, Action<T> proc) 
{ 
    proc(obj); 

    return obj; 
} 

powyższy przykład można zapisać następująco:

ContentPanel.Children.Add(
    new ListBox().Call(o => { 
      o.Width = 200; 
      o.MouseEnter += (s, e) => Console.WriteLine("MouseEnter"); 
      o.Items.Add(
       new Button().Call(b => { 
         b.Content = "abc"; 
         b.Click += (s, e) => Console.WriteLine("button 1 Click"); })); 
      o.Items.Add(
       new Button().Call(b => { 
        b.Content = "def"; 
        b.Click += (s, e) => Console.WriteLine("button 2 Click"); })); })); 

ja nie twierdzą, że jest ładna. :-) Ale zasadniczo pozwala na zastosowanie płynnego stylu.

+1

Czy po prostu nie szukają [inicjatorów obiektu] (http://msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx)? –

+2

Ataktory obiektów @SimonWhitehead działają tylko z właściwościami. Przykład obejmuje zdarzenia i wywołania metod. – juharr

+3

Myślę, że to, co masz, jest tak blisko, jak tylko możesz. I szczerze mówiąc nie uważam, że jest o wiele brzydsza niż przykład Dart. – juharr

Odpowiedz

3

Myślę, że można osiągnąć blisko tego, co chcesz osiągnąć, używając płynnego interfejsu. Pozwoli to na łańcuch metod do tworzenia i inicjowania obiektów w jednym wyciągu.

można dostać coś takiego:

Fluent fluent = new Fluent(); 
var panel = fluent.CreateControlPanel().Children() 
       .AddListBox().SetWidth(200).AddMouseEnterEvent((s, e) => { }).Create() 
       .AddTextBox().SetText("Foo").Create() 
       .GetControlPanel(); 

Chodzi o to, że metoda zwraca obiekt pozwalający zainicjować kolejny obiekt. Łańcuch inicjalizatora może wywołać w dowolnej pozycji metodę "finalizatora" (powyżej Create), która zwraca pierwotny obiekt (powyżej Children), aby kontynuować dodawanie innych obiektów lub konfigurację początkowego obiektu.

Na przykład w AddListBox zwraca obiekt typu ListBoxSetup, który ma wiele metod, takich jak SetWidth lub AddMouseEnterEvent. W tym przypadku obiekt specjalny (taki jak typ) będzie również obiektem specjalnym, takim jak AddListBox lub AddTextBox. Każda z metod ma za zadanie utworzyć obiekt typu ListBox lub TextBox lub ustawić właściwości obiektu, który ma zostać utworzony. Fluent będzie mieć metodę, która zwraca poprawnie całą strukturę obiektu.

Spójrz na ten link: http://blog.raffaeu.com/archive/2010/06/26/how-to-write-fluent-interface-with-c-and-lambda.aspx

Oto przykład kodu bazowego tworzyć skończyć z powyższych. Oczywiście kod mógł zostać znacznie ulepszony w swojej architekturze, ale jest tutaj tylko ze względu na przykład.

public class Fluent 
{ 
    public ControlPanelCreator CreateControlPanel() 
    { 
     return new ControlPanelCreator(new StackPanel(), this); 
    } 
} 

public class ControlPanelCreator 
{ 
    #region Fields 
    private Fluent fluent; 
    private Panel panel; 
    #endregion 

    #region Constructors 
    internal ControlPanelCreator(Panel panel, Fluent fluent) 
    { 
     this.fluent = fluent; 
     this.panel = panel; 
    } 
    #endregion 

    #region Methods 
    public ControlPanelChildrenCreator Children() 
    { 
     return new ControlPanelChildrenCreator(this.panel, this); 
    } 
    #endregion 
} 

public class ControlPanelChildrenCreator 
{ 
    #region Fields 
    private ControlPanelCreator panelCreator; 
    private Panel panel; 
    #endregion 

    #region Constructors 
    internal ControlPanelChildrenCreator(Panel panel, ControlPanelCreator panelCreator) 
    { 
     this.panel = panel; 
     this.panelCreator = panelCreator; 
    } 
    #endregion 

    #region Methods 
    public ListBoxCreator AddListBox() 
    { 
     ListBox listBox = new ListBox(); 
     this.panel.Children.Add(listBox); 
     return new ListBoxCreator(listBox, this); 
    } 

    public TextBoxCreator AddTextBox() 
    { 
     TextBox textBox = new TextBox(); 
     this.panel.Children.Add(textBox); 
     return new TextBoxCreator(textBox, this); 
    } 

    public Panel GetControlPanel() 
    { 
     return this.panel; 
    } 
    #endregion 
} 

public class ListBoxCreator 
{ 
    #region Fields 
    private ListBox listbox; 
    private ControlPanelChildrenCreator parentCreator; 
    #endregion 

    #region Constructors 
    internal ListBoxCreator(ListBox listBox, ControlPanelChildrenCreator parentCreator) 
    { 
     this.listbox = listBox; 
     this.parentCreator = parentCreator; 
    } 
    #endregion 

    #region Methods 
    public ListBoxCreator SetWidth(int width) 
    { 
     this.listbox.Width = width; 
     return this; 
    } 

    public ListBoxCreator AddMouseEnterEvent(Action<object, MouseEventArgs> action) 
    { 
     this.listbox.MouseEnter += new MouseEventHandler(action); 
     return this; 
    } 

    public ControlPanelChildrenCreator Create() 
    { 
     return this.parentCreator; 
    } 
    #endregion 
} 

public class TextBoxCreator 
{ 
    #region Fields 
    private TextBox textBox; 
    private ControlPanelChildrenCreator parentCreator; 
    #endregion 

    #region Constructors 
    internal TextBoxCreator(TextBox textBox, ControlPanelChildrenCreator parentCreator) 
    { 
     this.textBox = textBox; 
     this.parentCreator = parentCreator; 
    } 
    #endregion 

    #region Methods 
    public TextBoxCreator SetText(string defaultText) 
    { 
     this.textBox.Text = defaultText; 
     return this; 
    } 

    public ControlPanelChildrenCreator Create() 
    { 
     return this.parentCreator; 
    } 
    #endregion 
} 
0

Poparłem poprzednią odpowiedź. Niewiele rzeczy lubię dodawać, ponieważ stworzyłem podobne rzeczy.

Są dwie rzeczy: albo jedna klasa robi rzeczy. Oznacza formularz, ma addcolor, addData itd. I może mieć formę przycisk, a zamiast przycisku ma kolor

Teraz w tym przypadku musisz połączyć się za pomocą interfejsu, oznacza to, że typem powrotu będzie interfejs, a cały interfejs jest implementowany przez tę klasę i że metody zwracają tylko "to".

To wystarczy, gdy tworzysz obiekt interfejsu.A potem przeprowadź łańcuch. Trudno będzie podać przykład tutaj, ale jeśli nadal chcesz, mogę podać przykład.

Daj mi znać, jeśli jakieś szczegóły wymagane