我有以下接口声明:
interface IOrder<T> where T: IOrderItem
{
IList<T> Items { get; set; }
}
interface IOrderItem
{
IOrder<IOrderItem> Parent { get; set; } // What do I put here?
}
我希望列表中的项目具有对标题对象的引用,因此它可以使用标题中的ID和其他字段。
在我的具体课程中,它抱怨我没有正确实施“父”。
class StoreOrder : IOrder<StoreOrderItem>
{
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem : IOrderItem
{
public StoreOrder Parent { get; set; } // This doesn't satisfy the interface
}
我尝试将IOrderItem
设置为IOrderItem<T>
并传入父类型,但这导致循环引用,因为Header类需要Item类类型...我感到困惑。
有关如何正确实施此建议的任何建议吗?
答案 0 :(得分:3)
如果你这样定义你的界面:
interface IOrder<T> where T : IOrderItem<T>
{
IList<T> Items { get; set; }
}
interface IOrderItem<T> where T : IOrderItem<T>
{
IOrder<T> Parent { get; set; }
}
然后,您可以像这样实现它们以获得您期望的功能:
class StoreOrder : IOrder<StoreOrderItem>
{
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem: IOrderItem<StoreOrderItem>
{
public IOrder<StoreOrderItem> Parent { get; set; }
}
答案 1 :(得分:1)
class StoreOrder : IOrder<StoreOrderItem>
{
public int Id { get; set; }
}
class StoreOrderItem : IOrderItem
{
public IOrder<IOrderItem> Parent { get; set; } // This doesn't satisfy the interface
}
您可能不专业 - IOrder<IOrderItem>
比StoreOrder
答案 2 :(得分:1)
以下是更改界面的解决方案:
interface IOrder<TOrder, TOrderItem>
where TOrderItem : IOrderItem<TOrder>
{
IList<TOrderItem> Items { get; set; }
}
interface IOrderItem<TOrder>
{
TOrder Parent { get; set; }
}
对StoreOrder
和StoreOrderItem
进行更改以支持界面更改 AND 为每个属性添加一些属性,以便以后进行测试:
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
的{{1}}类型参数完全没有约束 - 尝试在其位置捏造其他类型(例如IOrderItem
)会导致编译错误。在没有类型约束的情况下,使用object
而不是仅调用它TOrder
会提示有关预期类型的提示。这将是我最后的编辑 - 我觉得这是我最简洁的尝试;如果你很好奇,我可以提供在接口上具有双通用约束类型的前实现,但这至少是我首选的解决方案。干杯!
答案 3 :(得分:0)
满足接口的声明:
class StoreOrder : IOrder<StoreOrderItem>
{
// interface members
public IList<StoreOrderItem> Items { get; set; }
// own members
public int Id { get; set; }
}
class StoreOrderItem : IOrderItem
{
public IOrder<IOrderItem> Parent { get; set; }
}
要访问自定义成员,您必须投射:
class StoreOrderItem : IOrderItem
{
void Test()
{
int id = ((StoreOrder)this.Parent).ID;
}
}