\"Fluent interfaces\" is a fairly hot topic these days. C# 3.0 has some nice features (particularly extension methods) that help you make them.
FYI, a fluent API means
I wrote a little fluent wrapper for System.Net.Mail which I find makes it email code much more readable (and easier to remember the syntax).
var email = Email
.From("john@email.com")
.To("bob@email.com", "bob")
.Subject("hows it going bob")
.Body("yo dawg, sup?");
//send normally
email.Send();
//send asynchronously
email.SendAsync(MailDeliveredCallback);
http://lukencode.com/2010/04/11/fluent-email-in-net/
I love the fluent interface in CuttingEdge.Conditions.
From their sample:
// Check all preconditions:
id.Requires("id")
.IsNotNull() // throws ArgumentNullException on failure
.IsInRange(1, 999) // ArgumentOutOfRangeException on failure
.IsNotEqualTo(128); // throws ArgumentException on failure
I've found that it is a lot easier to read, and makes me much more effective at checking my preconditions (and post conditions) in methods than when I have 50 if statements to handle the same checks.
The new HttpClient of the WCF REST Starter Kit Preview 2 is a great fluent API. see my blog post for a sample http://bendewey.wordpress.com/2009/03/14/connecting-to-live-search-using-the-httpclient/
Kudos for the method parameter validation, you've given me a new idea for our fluent APIs. I've hated our precondition checks anyways...
I've built a extensibility system for a new product in development, where you can fluently describe the commands available, the user interface elements and more. This runs on top of StructureMap and FluentNHibernate, which are nice APIs too.
MenuBarController mb;
// ...
mb.Add(Resources.FileMenu, x =>
{
x.Executes(CommandNames.File);
x.Menu
.AddButton(Resources.FileNewCommandImage, Resources.FileNew, Resources.FileNewTip, y => y.Executes(CommandNames.FileNew))
.AddButton(null, Resources.FileOpen, Resources.FileOpenTip, y =>
{
y.Executes(CommandNames.FileOpen);
y.Menu
.AddButton(Resources.FileOpenFileCommandImage, Resources.OpenFromFile, Resources.OpenFromFileTop, z => z.Executes(CommandNames.FileOpenFile))
.AddButton(Resources.FileOpenRecordCommandImage, Resources.OpenRecord, Resources.OpenRecordTip, z => z.Executes(CommandNames.FileOpenRecord));
})
.AddSeperator()
.AddButton(null, Resources.FileClose, Resources.FileCloseTip, y => y.Executes(CommandNames.FileClose))
.AddSeperator();
// ...
});
And you can configure all commands available like this:
Command(CommandNames.File)
.Is<DummyCommand>()
.AlwaysEnabled();
Command(CommandNames.FileNew)
.Bind(Shortcut.CtrlN)
.Is<FileNewCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Command(CommandNames.FileSave)
.Bind(Shortcut.CtrlS)
.Enable(WorkspaceStatusProviderNames.DocumentOpen)
.Is<FileSaveCommand>();
Command(CommandNames.FileSaveAs)
.Bind(Shortcut.CtrlShiftS)
.Enable(WorkspaceStatusProviderNames.DocumentOpen)
.Is<FileSaveAsCommand>();
Command(CommandNames.FileOpen)
.Is<FileOpenCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Command(CommandNames.FileOpenFile)
.Bind(Shortcut.CtrlO)
.Is<FileOpenFileCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Command(CommandNames.FileOpenRecord)
.Bind(Shortcut.CtrlShiftO)
.Is<FileOpenRecordCommand>()
.Enable(WorkspaceStatusProviderNames.DocumentFactoryRegistered);
Our view configure their controls for the standard edit menu commands using a service given to them by the workspace, where they just tell it to observe them:
Workspace
.Observe(control1)
.Observe(control2)
If the user tabs to the controls, the workspace automatically gets an appropriate adapter for the control and provides undo/redo and clipboard operations.
It has helped us reduce the setup code dramatically and make it even more readable.
I forgot to tell about a library we're using in our WinForms MVP model presenters to validate the views: FluentValidation. Really easy, really testable, really nice!
As @John Sheehan mentioned, Ninject uses this type of API to specify bindings. Here are some example code from their user guide:
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf();
Bind<Shogun>().ToSelf().Using<SingletonBehavior>();