根据上一个问题,我改变了上下文:
我有一个名为Tenant和CustomerList的抽象类。在这种情况下,租户就像多租户应用程序模型的应用程序的所有者,而CustomerList是Customer类的集合。
这两个阶级之间的关系是多对一的关系。
public abstract class Tenant
{
protected Int32 id;
protected String name;
public Int32 ID { get; set; }
public String Name { get; set; }
public abstract bool Add();
public abstract bool Update();
public abstract bool Delete();
}
public class ApplicationTenant: Tenant
{
public ApplicationTenant() { }
public override Int32 ID
{
get { return id; }
set { id = value; }
}
public override String Name
{
get { return name; }
set { name= value; }
}
}
public abstract class CustomerList
{
protected Tenant tenant;
public abstract Tenant Tenant {get; set;}
public abstract List<Customer> GetAll();
}
public abstract class CorporateCustomerList : CustomerList
{
privateT enant tenant;
public override Tenant Tenant
{
get(return tenant;) ;
set(Tenant = tenant);
}
public override List<Customer> GetAll()
{
... calling from data service
return t;
}
}
通过上面的OO设计,我们知道List GetAll()的方法;需要被压倒。
但问题是:
1) CorporateCustomer 中GetAll()
的返回值始终为List<CorporateCustomer>.
我必须覆盖List<Customer> Get()
而不实施并创建另一个跟随方法
public List<CorporateCustomer > GetAll() { return ???; }
2)如果我仍然覆盖上面的这个方法,并且在返回时我只是投了它......它无论如何都无法工作。 ?!!?无法从列表中转换为列表
3)以下属性:
public override Tenant Tenant
{
get { return tenant; }
set { tenant= value; }
}
意味着我必须重写这个BUTI我不是真的使用过这个因为 CorporateCustomer 总是会被用作ApplicationTenant而不是返回NOT Tenant。
public CorporateTenant Tenant
{
get { return corporateTenant; }
set { corporateTenant= value; }
}
这是正确的设计吗?因为它有点浪费抽象。
有些人建议使用Generic抽象类,但我不确定它是否会有所帮助。我确实尝试在方法上使用泛型,但定义的定义需要从顶层的abstrction开始。
由于
答案 0 :(得分:1)
不幸的是,你遇到过(IMO)C#的两个主要缺陷和陷阱 - 覆盖和通用的共同和反向差异。我将以最明智的顺序解决问题
关于问题3,您不能使用返回SubClass的方法覆盖返回BaseClass的方法。 C#不允许您在覆盖时更改方法参数,即使更改是类型安全的,并且从我收集的内容中也不会很快解决,因为它是一个非常严重的突破性更改,并且依赖于CLR。解决方法是将CustomerList更改为一个接口(应该没问题,因为它只有抽象成员)并执行类似这样的操作(暂时忽略GetAll):
public interface ICustomerList
{
Tenant Tenant {get; set;}
}
public abstract class CorporateCustomerList : ICustomerList
{
private CorporateTenant tenant;
public CorporateTenant Tenant
{
get { return tenant; }
set { tenant = value; }
}
Tenant ICustomerList.Tenant
{
get { return Tenant; }
set { Tenant = value; }
}
}
GetAll的另一个问题是List<BaseClass>
无法以任何方式转换或转换为List<SubClass>
- 这是SO上的常见问题,并且将针对C#4中的通用接口进行解决。有几种解决方法:
使用数组存储客户,让GetAll返回IList而不是List,并使用上面的显式接口实现覆盖 - 由于历史原因,数组执行支持元素类型协方差(抱歉格式化,降价似乎做了奇怪的事情)
public interface ICustomerList
{
public IList<Customer> GetAll();
}
public abstract class CorporateCustomerList : ICustomerList
{
private CorporateCustomer[] customers;
public IList<CorporateCustomer> GetAll()
{
get { return customers; }
set { customers= value; }
}
IList<Customer> ICustomerList.GetAll()
{
get { return customers; }
set { customers = value; }
}
}
更改GetAll以返回IEnumerable<T>
而不是List<T>
,然后使用yield return语法将IEnumerable<CorporateCustomer>
转换为IEnumerable<Customer>
,但稍微使用二传手更复杂...
public abstract class CorporateCustomerList : ICustomerList
{
// as above...
private CorporateCustomer[] customers;
IEnumerable<Customer> ICustomerList.GetAll()
{
get
{
foreach (CorporateCustomer c in customers)
{
yield return c;
}
}
}
}
希望这会给你一些想法......
答案 1 :(得分:0)
但是租户实际上是一个人/实体,其“合同”被称为“租约”.....由于没有足够的背景,我不确定你的其余问题
答案 2 :(得分:0)
另外,只要您在任何应用程序中代表真人,请考虑使用Person
和Role
类。这样,您可以给任何Person
任意数量的职责,而且您不必创建奇怪而精彩的类层次结构。
对于您的示例,您将有几个角色:
public class Customer : Role
{
...
}
public class CorporateCustomer : Role
{
...
}
public class Tenant : Role
{
...
}
一个看起来像这样的Person类:
public class Person
{
Details Details {get;set;}
IList<Role> Roles {get;set;}
}
使用Role类封装适当的逻辑。