2

I never used the fluent code style before. So this is hte first time I tried to develop something in the fluent style with a C# property declaration, but I get an error. Can anyone help me?

public class MailTemplate
{
    string _MailBody = "";
    public MailTemplate MailBody
    {
        get { return _MailBody; }
        set { _MailBody = value ; }
    }

    string _Subject = "";
    public MailTemplate Subject
    {
        get { return _Subject; }
        set { _Subject = value; }
    }

    string _MailFrom = "";
    public MailTemplate MailFrom
    {
        get { return _MailFrom; }
        set { _MailFrom = value; }
    }
}

Please help me how I could assign or initialize the mail body and later also can read with same property name. I think a property cannot be used in case of fluent style development. Need some light here.

Thomas
  • 33,544
  • 126
  • 357
  • 626

4 Answers4

6

A fluent builder interface for the MailTemplate class would look something like this:

public class MailTemplateBuilder
{
    string _body;
    string _subject;
    string _sender;

    public MailTemplateBuilder WithBody(string body)
    {
        _body = body;
        return this;
    }

    public MailTemplateBuilder WithSubject(string subject)
    {
        _subject = subject;
        return this;
    }

    public MailTemplateBuilder WithSender(string sender)
    {
        _sender = sender;
        return this;
    }

    public MailTemplate Build()
    {
        return new MailTemplate(_sender, _subject, _body);
    }
}

Usage would look like this:

var template = _builder.WithBody("body")
                       .WithSubject("subject")
                       .WithSender("sender")
                       .Build();

Another approach would be to use extension methods:

public static class MailTemplateBuilder
{
    public static MailTemplate WithBody(this MailTemplate item, string body)
    {
        item.MailBody = body;
        return item;
    }

    public static MailTemplate WithSubject(this MailTemplate item, string subject)
    {
        item.MailSubject = subject;
        return item;
    }

    public static MailTemplate WithSender(this MailTemplate item, string sender)
    {
        item.MailFrom = sender;
        return item;
    }
}

Usage would now look like this:

var template = new MailTemplate().WithBody("body")
                                 .WithSubject("subject")
                                 .WithSender("sender");

Please note:
In both cases, the MailTemplate class is not polluted with code for this fluent interface. It would be a simple class:

public class MailTemplate
{
    public string MailBody { get; set; } = "";
    public string Subject { get; set; } = "";
    public string MailFrom { get; set; } = "";
}

So, after you created that instance with any one of the provided fluent interfaces, you can simply read the values by accessing the properties:

var body = template.MailBody;
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
4

Some frameworks e.g. FluentNHibernate just pass themselves as a lambda for this:

MailTemplate
    .ConfigureWith(mt => mt.MailBody = "hello world")
    .ConfigureWith(mt => mt.MailFrom = "rdingwall@gmail.com")
    .DoSomeOtherStuff()
    .Build();

The implementation for this would be:

public class MailTemplate
{
    // regular auto properties
    public string MailFrom { get; set; }
    public string MailBody { get; set; }

    public MailTemplate ConfigureWith(Action<MailTemplate> func)
    {
        func(this);
        return this;
    }

    ...
}
Richard Dingwall
  • 2,692
  • 1
  • 31
  • 32
  • your ConfigureWith() function expects one delegate but when u use the code like .ConfigureWith(mt => mt.MailBody = "hello world") it means you are passing string data to ConfigureWith() function but it expects one delegate. it is bit confusing for me. can u tell how it works. thanks – Thomas Dec 07 '12 at 12:21
  • another important thing is can i use your code in .net version 2.0 ?? – Thomas Dec 07 '12 at 12:41
  • when i am trying to compile your code in c# v2.0 then i am getting error. c# 2.0 does not support lambda? – Thomas Dec 07 '12 at 13:21
  • It's called a lambda expression, it's a shorthand form of a delegate that's easier to read. In this case, assigning a string value to a property. And yes I just checked, it compiles fine in VS2010 targeting .NET 2.0. – Richard Dingwall Dec 07 '12 at 17:37
  • ConfigureWith not static. `new MailTemplate().ConfigureWith` ? – Kiquenet Mar 23 '21 at 08:47
2

You can't use properties like that to write a fluent interface - the fields are of type string but your properties all try to return a MailTemplate.

Instead of properties, make these into methods that can be chained together.

public class MailTemplate
{
    string _MailBody = "";

    public MailTemplate Body(string mailBody)
    {
        _MailBody = mailBody;
        return this;
    }

    ...
Oded
  • 489,969
  • 99
  • 883
  • 1,009
2

As @Richard said, FluentNHibernate just pass themselves as a lambda. you can also do the same using c#.

public class MailTemplate
{
   
    public string To { get; set; }
    public string From { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }
    public string Attachement { get; set; }

    public static MailTemplate Configure { get => new MailTemplate(); }


    public MailTemplate With(Action<MailTemplate> func)
    {
        func(this);
        return this;
    }

    internal void Build()
    {
        Console.WriteLine("Sending the mail....");
    }
}

This is how to call this method

MailTemplate
            .Configure
                .With(mt => mt.To = "michaelameyaw7@gmail.com")
                .With(mt => mt.From = "persol.system@gmail.com")
                .With(mt => mt.Subject = "Fluent Try Test")
                .With(mt => mt.Body = "Hello, this is mail body")
                .With(mt => mt.Attachement = "file.pdf")
           .Build();
mkojoa
  • 53
  • 9