64

例によって問題を示します。流暢なインターフェースを持つ基本クラスがあります:

class FluentPerson
{
    private string _FirstName = String.Empty;
    private string _LastName = String.Empty;

    public FluentPerson WithFirstName(string firstName)
    {
        _FirstName = firstName;
        return this;
    }

    public FluentPerson WithLastName(string lastName)
    {
        _LastName = lastName;
        return this;
    }

    public override string ToString()
    {
        return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
    }
}

および子クラス:

class FluentCustomer : FluentPerson
{
    private long _Id;

    private string _AccountNumber = String.Empty;

    public FluentCustomer WithAccountNumber(string accountNumber)
    {
        _AccountNumber = accountNumber;
        return this;
    }
    public FluentCustomer WithId(long id)
    {
        _Id = id;
        return this;
    }

    public override string ToString()
    {
        return base.ToString() + String.Format(" account number: {0} id: {1}", _AccountNumber, _Id);
    }
}

問題は、メソッドの戻り値の型が FluentPerson (FluentCustomer ではない)であるため、呼び出すときに最後にcustomer.WithAccountNumber("000").WithFirstName("John").WithLastName("Smith")追加できないことです。.WithId(123)WithLastName()

この問題は通常どのように解決されますか?

4

7 に答える 7

49

いくつかの拡張メソッドを使用してみてください。

static class FluentManager
{
    public static T WithFirstName<T>(this T person, string firstName) where T : FluentPerson
    {
        person.FirstName = firstName;
        return person;
    }

    public static T WithId<T>(this T customer, long id) where T : FluentCustomer
    {
        customer.ID = id;
        return customer;
    }
}

class FluentPerson
{
    public string FirstName { private get; set; }
    public string LastName { private get; set; }

    public override string ToString()
    {
        return string.Format("First name: {0} last name: {1}", FirstName, LastName);
    }
}

class FluentCustomer : FluentPerson
{
    public long ID { private get; set; }
    public long AccountNumber { private get; set; }

    public override string ToString()
    {
        return base.ToString() + string.Format(" account number: {0} id: {1}", AccountNumber, ID);
    }
}

のように使用できるようになった後

new FluentCustomer().WithId(22).WithFirstName("dfd").WithId(32);
于 2010-02-17T07:39:55.853 に答える
4

論理的には、最も具体的なもの (顧客) から最も具体的でないもの (人) までを構成する必要があります。ほとんどの場合、このルールに従えば、トラブルに巻き込まれることはありません。ただし、何らかの理由でまだ混合する必要がある場合は、次のような中間の強調ステートメントを使用できます

static class Customers
{
   public static Customer AsCustomer(this Person person)
   {
       return (Customer)person;
   }
}

customer.WIthLastName("Bob").AsCustomer().WithId(10);
于 2010-02-17T06:47:05.193 に答える
4

流暢なインターフェイス、継承、およびいくつかのジェネリックが必要なソリューション...

とにかく、前に述べたように、継承を使用し、保護されたメンバーにもアクセスしたい場合、これが唯一のオプションです...

public class GridEx<TC, T> where TC : GridEx<TC, T>
{
    public TC Build(T type)
    {
        return (TC) this;
    }
}

public class GridExEx : GridEx<GridExEx, int>
{

}

class Program
{
    static void Main(string[] args)
    {
        new GridExEx().Build(1);
    }
}
于 2015-10-15T05:32:04.087 に答える
3
 public class FluentPerson
 {
    private string _FirstName = String.Empty;
    private string _LastName = String.Empty;

    public FluentPerson WithFirstName(string firstName)
    {
        _FirstName = firstName;
        return this;
    }

    public FluentPerson WithLastName(string lastName)
    {
        _LastName = lastName;
        return this;
    }

    public override string ToString()
    {
        return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
    }
}


   public class FluentCustomer 
   {
       private string _AccountNumber = String.Empty;
       private string _id = String.Empty;
       FluentPerson objPers=new FluentPerson();



       public FluentCustomer WithAccountNumber(string accountNumber)
       {
           _AccountNumber = accountNumber;
           return this;
       }

       public FluentCustomer WithId(string id)
       {
           _id = id;
           return this;
       }

       public FluentCustomer WithFirstName(string firstName)
       {
           objPers.WithFirstName(firstName);
           return this;
       }

       public FluentCustomer WithLastName(string lastName)
       {
           objPers.WithLastName(lastName);
           return this;
       }


       public override string ToString()
       {
           return objPers.ToString() + String.Format(" account number: {0}",  _AccountNumber);
       }
   }

そしてそれを使用して呼び出します

  var ss = new FluentCustomer().WithAccountNumber("111").WithFirstName("ram").WithLastName("v").WithId("444").ToString();
于 2010-02-17T06:48:45.643 に答える
3

ここでは流暢なインターフェイスが本当に最適な呼び出しですか、それともイニシャライザの方が優れているでしょうか?

 var p = new Person{
      LastName = "Smith",
      FirstName = "John"
      };

 var c = new Customer{
      LastName = "Smith",
      FirstName = "John",
      AccountNumber = "000",
      ID = "123"
      };

流暢なインターフェイスとは異なり、これは継承されたメソッドが基本クラスを返してチェーンを台無しにすることなく正常に機能します。FirstNameプロパティを継承する場合、呼び出し元は、最初に実装されたのが Person か Customer か Objectかを気にする必要はありません。

これは、1 行であろうと複数行であろうと、読みやすい思います。また、各プロパティに対応する流暢な自己装飾関数を提供するという問題を経験する必要はありません。

于 2010-02-17T07:10:30.037 に答える