以下是更改接口的解决方案:
interface IOrder<TOrder, TOrderItem>
where TOrderItem : IOrderItem<TOrder>
{
IList<TOrderItem> Items { get; set; }
}
interface IOrderItem<TOrder>
{
TOrder Parent { get; set; }
}
更改StoreOrder 和StoreOrderItem 以支持接口更改并为每个属性添加几个属性以供以后测试:
class StoreOrder: IOrder<StoreOrder, StoreOrderItem>
{
public DateTime Date { get; set; }
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem : IOrderItem<StoreOrder>
{
public string ItemName { get; set; }
public decimal ItemPrice { get; set; }
public StoreOrder Parent { get; set; }
}
...现在创建 StoreOrder 和 StoreOrderItem 实例,并逐步完成它们:
void Main()
{
var so = new StoreOrder { Date = DateTime.Now };
var item = new StoreOrderItem {
Parent = so,
ItemName = "Hand soap",
ItemPrice = 2.50m };
so.Items = new [] { item };
Console.WriteLine(item.Parent.Date);
Console.WriteLine(so.Items.First().ItemName);
}
...运行时,打印:
3/16/2012 10:43:55 AM
Hand soap
另一种选择是废弃上述内容并采用 this solution 并通过添加具有所需类型的 Parent 属性并使用显式接口实现来避免在调用站点进行强制转换来更改它,从而使 StoreOrderItem 实现类似于这个:
class StoreOrderItem : IOrderItem
{
public string ItemName { get; set; }
public decimal ItemPrice { get; set; }
public StoreOrder Parent { get; set; } // note: original implementation
IOrder<IOrderItem> IOrderItem.Parent { // explicit interface implementation
get { return (IOrder<IOrderItem>)this.Parent; }
set { this.Parent = (StoreOrder)value; }
}
}
我最喜欢上面的第一个提案,上面有两个泛型参数IOrder 和IOrderItem 上的无约束泛型参数。我发布并现在编辑的先前版本具有两个接口,每个接口都具有相同的两个泛型类型,每个具有相同的约束。我觉得这有点过火了,所以我将其缩减为上述实现。尽管 TOrder 类型参数对 IOrderItem 完全没有约束 - 尝试在其位置上捏造其他类型(例如,object)会导致编译错误。在没有类型约束的情况下,使用TOrder 而不是仅仅调用它T 提供了关于预期类型的提示。那将是我的最后一次编辑——我觉得这是我尝试中最简洁的一次;如果您好奇,我可以提供在接口上具有双泛型约束类型的前一个实现,但这至少是我更喜欢的解决方案。干杯!