如何组织彼此继承的C#类,还具有彼此继承的属性?

Chr*_*ris 8 c# oop entity-framework

我有一个应用程序,它有一个概念,Venue即事件发生的地方.A Venue有很多个VenuePart.所以,它看起来像这样:

public abstract class Venue
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<VenuePart> VenueParts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

A Venue可以GolfCourseVenue是a Venue,具有Slope和特​​定类型的VenueParta HoleVenuePart:

public class GolfCourseVenue : Venue
{
    public string Slope { get; set; }
    public virtual ICollection<HoleVenuePart> Holes { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在未来,可能还有其他种类的Venues都继承自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; }
}
Run Code Online (Sandbox Code Playgroud)

我上面的声明似乎是错误的,因为现在我有一个GolfCourseVenue有两个集合,真的应该只有一个.我无法覆盖它,因为类型不同,对吧?当我运行报告时,我想通常引用这些类,我只是吐出Venues和VenueParts.但是,当我渲染表格等时,我想具体一点.

我有很多像这样的关系,我想知道我做错了什么.例如,我有一个OrderOrderItemS,也是特定种类的OrderS作特定种类的OrderItem秒.

更新:我应该注意这些类是实体框架代码优先实体.我希望这没关系,但我想可能会这样.我需要以Code-First可以正确创建表的方式构造类.它看起来不像Code-First可以处理泛型.对不起,这个实现细节正在妨碍优雅的解决方案:/

更新2:有人链接到指向协方差和逆变的搜索,这似乎是一种将子类型中的列表限制为给定子类型的方法.这似乎很有希望,但这个人删除了他们的答案!有没有人知道如何利用这些概念?

更新3:删除了子对象中的导航属性,因为它使人们感到困惑并且没有帮助描述问题.

Phi*_*hil 2

这是使用泛型的一种可能的选择:

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>
{
}
Run Code Online (Sandbox Code Playgroud)

这里 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
{
}
Run Code Online (Sandbox Code Playgroud)

现在 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); }
}
Run Code Online (Sandbox Code Playgroud)