[英]How do I organize C# classes that inherit from one another, but also have properties that inherit from one another?
我有一个具有Venue
概念的应用程序,即发生事件的地方。 一个Venue
有许多VenuePart
。 因此,它看起来像这样:
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
Venue
可以是GolfCourseVenue
,这是一个具有坡度和特定种类的VenuePart
的Venue
,该VenuePart
称为HoleVenuePart
:
public class GolfCourseVenue : Venue
{
public string Slope { get; set; }
public virtual ICollection<HoleVenuePart> Holes { get; set; }
}
将来,可能还会有其他种类的Venue
都继承自Venue
。 他们可以添加自己的字段,并且始终具有自己特定类型的VenuePart
。
以下是VenuePart
类:
public abstract class VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public override string NameDescriptor { get { return "Hole"; } }
public int Yardage { get; set; }
}
我上面的声明似乎是错误的,因为现在我有一个带有两个集合的GolfCourseVenue
,而实际上它应该只有一个。 我不能覆盖它,因为类型不同,对吗? 运行报表时,我想VenuePart
地引用这些类,在这些类中,我只吐出了Venue
和VenuePart
。 但是,当我渲染表格等时,我想具体一点。
我有很多这样的关系,想知道我做错了什么。 例如,我有一个Order
有OrderItem
S,也特定种类的Order
S作特定种类的OrderItem
秒。
更新:我应该注意这些类是Entity Framework Code-First实体。 我希望这没关系,但我想可能会。 我需要以Code-First可以正确创建表的方式来构造类。 看起来Code-First不能处理泛型。 抱歉,此实现细节妨碍了一种优雅的解决方案:/
更新2:有人链接到指向协方差和相反方差的搜索,这似乎是一种将子类型内的列表约束为给定子类型本身的方法。 这看起来确实很有希望,但是此人删除了答案! 是否有人知道我如何利用这些概念?
更新3:删除了子对象中的导航属性,因为它使人们感到困惑,并且无法帮助描述问题。
这是使用泛型的一种可能的选择:
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public string NameDescriptor { get{return "I'm a hole venue"; } }
}
public class Venue<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
}
GolfCourseVenue在这里具有VenueParts集合,其中可以包含HoleVenueParts或超类HoleVenueParts。 Venue的其他专业化将VenueParts限制为包含特定于该场所的VenueParts。
第二种可能性与您所拥有的差不多
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public string NameDescriptor { get{return "I'm a hole venue"; } }
}
public class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue
{
}
现在,GolfCourseVenue具有集合VenueParts,该集合可以包含VenueParts或超类VenueParts。 在这里,Venue的所有专业化都可以包含任何类型的VenuePart,无论适当与否。
为了回答您对协方差的评论,我将提出如下建议:
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public override string NameDescriptor { get{return "I'm a hole venue"; } }
}
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public abstract ICollection<VenuePart> VenueParts { get; }
}
public class GolfCourseVenue : Venue
{
private ICollection<HoleVenuePart> _holeVenueParts;
public GolfCourseVenue(ICollection<HoleVenuePart> parts)
{
_holeVenueParts = parts;
}
public override ICollection<VenuePart> VenueParts
{
get
{
// Here we need to prevent clients adding
// new VenuePart to the VenueParts collection.
// They have to use Add(HoleVenuePart part).
// Unfortunately only interfaces are covariant not types.
return new ReadOnlyCollection<VenuePart>(
_holeVenueParts.OfType<VenuePart>().ToList());
}
}
public void Add(HoleVenuePart part) { _holeVenueParts.Add(part); }
}
您可以使用协方差
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual IEnumerable<VenuePart> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue
{
public string Slope { get; set; }
public GolfCourseVenue()
{
List<HoleVenuePart> HoleVenueParts = new List<HoleVenuePart>();
HoleVenueParts.Add(new HoleVenuePart());
VenueParts = HoleVenueParts;
}
}
假设HoleVenuePart继承自VenuePart
我期待其他人的建议-但我的方法是在这种情况下使用泛型。 使用泛型,您的GolfCourseVenue
的“零件”是强类型的!
...当我输入此字时,其他所有人也都在说泛型。 您如何快速输入叠放器?
无论如何,假装我还是第一-
public class VenuePart
{
}
public class HoleVenuePart : VenuePart
{
}
public abstract class Venue<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> Parts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
public string Slope { get; set; }
}
此外,作为第二选项,你可以用一个接口也一样,所以如果你不喜欢这个名字Parts
,你可以把它叫做Holes
时的派生型被称为是一个园高尔夫球场
public class VenuePart
{
}
public class HoleVenuePart : VenuePart
{
}
public interface IPartCollection<T> where T : VenuePart
{
ICollection<T> Parts { get; set; }
}
public abstract class Venue<T> : IPartCollection<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> Parts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
public string Slope { get; set; }
ICollection<HoleVenuePart> IPartCollection<HoleVenuePart>.Parts { get { return base.Parts; } set { base.Parts = value; }}
public virtual ICollection<HoleVenuePart> Holes { get { return base.Parts; } set { base.Parts = value;}}
}
如果删除两个集合的“集合”部分,则将更有意义:基类提供“所有部分”集合,而派生类除了具有基类一外,还具有过滤视图。
注意:根据您的需要,可能使GolfVenue成为Venue<VenuePart>
专业通用类,因为Venue<Type1>
和Venue<Type2>
将没有任何好的基础类可以使用。
考虑使用接口而不是基类,因为这将使实现更具灵活性。
public interface IVenue
{
public int Id { get; }
public string Name { get; }
public virtual IEnumerabe<VenuePart> VenueParts { get; }
}
public interface IGolfCourse : IVenue
{
public virtual IEnumerabe<HoleVenuePart> Holes { get; }
}
现在,您可以使用其他示例中的GolfCourse:Venue,但是由于它实现了接口,因此您也可以以普通的方式来处理它:
class GolfCourse:Venue<HoleVenuePart>, IGolfCourse {
public virtual IEnumerabe<VenuePart> Holes{ get
{
return VenueParts.OfType<HoleVenuePart>();
}
}
}
class OtherPlace:Venue<VenuePart>, IVenue {...}
List<IVenue> = new List<IVenue> { new GolfCourse(), new OtherPlace() };
GolfCourse
, GolfCourse
和OtherPlace
没有共同的父类(对象除外),因此没有接口,就不能互换使用它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.