The Dart programming language has support for method cascades. Method cascades would allow the following Silverlight/WPF C# code:
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);
to be written instead as:
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"))));
My question is, is there a way to simulate or closely approximate method cascades in C#?
Here's one approach I came up with. Given this extension method:
public static T Call<T>(this T obj, Action<T> proc)
{
proc(obj);
return obj;
}
the above example can be written as follows:
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"); })); }));
I wouldn't argue that that's pretty. :-) But it does essentially enable a fluent style to be applied.
I think you can reach close to what you want to achieve by using fluent interface. It will allow you to chain methods to create and initialize objects in one statement.
You can get something like that:
The idea is that a method returns an object allowing to initialize another object. A chain of initializer can call at any item a "finalizer" method (above
Create) that returns the original object (aboveChildren) to continue to add other objects or configure the initial one.So for example in
AddListBoxreturns an object of typeListBoxSetupwhich has a bunch of methods likeSetWidthorAddMouseEnterEvent. In this caseChildrenwill also be a special object (like of typeChildSetup) which has a bunch of methods such asAddListBoxorAddTextBox. Each of the method has in charge to create an object of typeListBoxorTextBoxor setup properties of the underlying object to be created.Fluentwill have a method that returns your whole object structure correctly setup.Take a look to this link: http://blog.raffaeu.com/archive/2010/06/26/how-to-write-fluent-interface-with-c-and-lambda.aspx
Here's an example of the underlying code create to end up with the above. Of course the code could be greatly improved in its architecture but it's here just for the sake of the example.