给定以下示例控制台应用程序:
问题1:为什么.Name()返回OranizationBuilder的类型,而.Write()调用CorporationBuilder?
问题2:如何获取.Name()返回CorporationBuilder的类型?
namespace MyCompany
{
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Environment.NewLine);
Factory.Organization()
.ID(33)
.Name("Oranization A")
.Write();
Console.WriteLine("\n----------------------------\n");
Factory.Corporation()
.Date(DateTime.Today) // Pass
.ID(44)
.Name("Company B")
// .Date(DateTime.Today) // Fail
.Write();
// QUESTION #1: Why does .Name() return typeof OranizationBuilder,
// but .Write() calls CorporationBuilder?
// QUESTION #2: How to get .Name() to return typeof CorporationBuilder?
Console.ReadLine();
}
}
/* Business Classes */
public abstract class Contact
{
public int ID { get; set; }
}
public class Organization : Contact
{
public string Name { get; set; }
}
public class Corporation : Organization
{
public DateTime Date { get; set; }
}
/* Builder */
public abstract class ContactBuilder<TContact, TBuilder>
where TContact : Contact
where TBuilder : ContactBuilder<TContact, TBuilder>
{
public ContactBuilder(TContact contact)
{
this.contact = contact;
}
private TContact contact;
public TContact Contact
{
get
{
return this.contact;
}
}
public virtual TBuilder ID(int id)
{
this.Contact.ID = id;
return this as TBuilder;
}
public virtual void Write()
{
Console.WriteLine("ID : {0}", this.Contact.ID);
}
}
public class OrganizationBuilder : ContactBuilder<Organization, OrganizationBuilder>
{
public OrganizationBuilder(Organization contact) : base(contact) { }
public virtual OrganizationBuilder Name(string name)
{
(this.Contact as Organization).Name = name;
return this;
}
public override void Write()
{
base.Write();
Console.WriteLine("Name : {0}", this.Contact.Name);
}
}
public class CorporationBuilder : OrganizationBuilder
{
public CorporationBuilder(Corporation contact) : base(contact) { }
public virtual CorporationBuilder Date(DateTime date)
{
// Cast is required, but need this.Contact to be typeof 'C'
(this.Contact as Corporation).Date = date;
return this;
}
public override void Write()
{
base.Write();
Console.WriteLine("Date : {0}", (this.Contact as Corporation).Date.ToShortDateString());
}
}
/* Factory */
public class Factory
{
public static OrganizationBuilder Organization()
{
return new OrganizationBuilder(new Organization());
}
public static CorporationBuilder Corporation()
{
return new CorporationBuilder(new Corporation());
}
}
}
编辑/更新
这是我的第一个尝试解决方案的方法(请参阅下文),尽管我被困在Factory中并且不确定如何配置.Organization()和.Corporation()方法类型。
namespace MyCompany
{
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Environment.NewLine);
Factory.Organization()
.ID(33)
.Name("Oranization A")
.Write();
Console.WriteLine("\n----------------------------\n");
Factory.Corporation()
.ID(44)
.Name("Company B")
.Date(DateTime.Today)
.Write();
Console.ReadLine();
}
}
/* Business Classes */
public abstract class Contact
{
public int ID { get; set; }
}
public class Organization : Contact
{
public string Name { get; set; }
}
public class Corporation : Organization
{
public DateTime Date { get; set; }
}
/* Builder */
public abstract class ContactBuilder<TContact, TBuilder>
where TContact : Contact
where TBuilder : ContactBuilder<TContact, TBuilder>
{
public ContactBuilder(TContact contact)
{
this.contact = contact;
}
private TContact contact;
public TContact Contact
{
get
{
return this.contact;
}
}
public virtual TBuilder ID(int id)
{
this.Contact.ID = id;
return this as TBuilder;
}
public virtual void Write()
{
Console.WriteLine("ID : {0}", this.Contact.ID);
}
}
public class OrganizationBuilder<TOrganization, TBuilder> : ContactBuilder<TOrganization, TBuilder> where TOrganization : Organization where TBuilder : OrganizationBuilder<TOrganization, TBuilder>
{
public OrganizationBuilder(TOrganization contact) : base(contact) { }
public virtual TBuilder Name(string name)
{
this.Contact.Name = name;
return this as TBuilder;
}
public override void Write()
{
base.Write();
Console.WriteLine("Name : {0}", this.Contact.Name);
}
}
public class CorporationBuilder<TCorporation, TBuilder> : OrganizationBuilder<TCorporation, TBuilder> where TCorporation : Corporation where TBuilder : CorporationBuilder<TCorporation, TBuilder>
{
public CorporationBuilder(TCorporation contact) : base(contact) { }
public virtual TBuilder Date(DateTime date)
{
this.Contact.Date = date;
return this as TBuilder;
}
public override void Write()
{
base.Write();
Console.WriteLine("Date : {0}", this.Contact.Date.ToShortDateString());
}
}
/* Factory */
public class Factory
{
public static OrganizationBuilder<Organization, OrganizationBuilder> Organization()
{
return new OrganizationBuilder<Organization, OrganizationBuilder>(new Organization());
}
public static CorporationBuilder<Corporation, CorporationBuilder> Corporation()
{
return new CorporationBuilder<Corporation, CorporationBuilder>(new Corporation());
}
}
}
这是特定的问题区域:
/* Factory */
public class Factory
{
public static OrganizationBuilder<Organization, OrganizationBuilder> Organization()
{
return new OrganizationBuilder<Organization, OrganizationBuilder>(new Organization());
}
public static CorporationBuilder<Corporation, CorporationBuilder> Corporation()
{
return new CorporationBuilder<Corporation, CorporationBuilder>(new Corporation());
}
}
如何配置OrganizationBuilder和CorportationBuilder?
最佳答案
当Name
返回引用时,它将返回this
-因此,当实例实际上是CorporationBuilder
的实例时,该引用将正常返回。仅仅因为方法声明为返回OrganizationBuilder
并不意味着它仅返回OrganizationBuilder
引用。它返回对OrganizationBuilder
实例的实例或派生类(当然是null
)的引用。
然后调用Write
方法时,这是一个虚拟方法,因此将检查对象的执行时间类型以找到要使用的实现。执行时间类型仍为CorporationBuilder
,因此使用该类型中指定的替代。
至于如何使Name()
返回适当的类型-基本上将需要更多的泛型。可以做到,但是很痛苦-我在Protocol Buffers中做了类似的事情,但这并不令人愉快。您还要在OrganizationBuilder
和TContact
中使TBuilder
通用,并使Name
通过从TBuilder
到this
的转换返回TBuilder
。然后CorporationBuilder
也可以是通用的,也可以只是继承自OrganizationBuilder<Corporation, CorporationBuilder>
。
编辑:是的,我看到了这个问题(之前我已经忘记了)。您可能还希望有一个名为CorporationBuilder
的具体非泛型类,以避免递归泛型:
public class OrganizationBuilder :
OrganizationBuilder<Organization, OrganizationBuilder>
您可能还想将
OrganizationBuilder
重命名为OrganizationBuilderBase
以避免混淆:)(如果
CorporationBuilder
位于层次结构的底部,则不需要本身就是通用的。)但是,这变得极其复杂。您可能至少要考虑在这里避免继承。取消泛型,并使
OrganizationBuilder
具有CorporationBuilder
而不是从中派生。基本上,这种模式在一段时间后总会变得很复杂-您最终需要除叶节点之外的每个级别都是通用的,叶节点始终需要是非通用的,以避免您已经看到的递归问题。真痛苦
关于c# - C#中具有流畅接口(interface)的多级继承,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1352378/