如何组织相互继承的C#类,同时也具有相互继承的属性?
我有一个应用程序,它有一个如何组织相互继承的C#类,同时也具有相互继承的属性?,c#,entity-framework,oop,C#,Entity Framework,Oop,我有一个应用程序,它有一个场所的概念,一个事件发生的地方。一个场馆有许多VenueParts。所以,看起来是这样的: public abstract class Venue { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<VenuePart> VenueParts { get; set; } } public abstract
场所的概念,一个事件发生的地方。一个场馆
有许多VenuePart
s。所以,看起来是这样的:
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
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); }
}
将来,可能还会有其他类型的场馆
都继承自场馆
。他们可以添加自己的字段,并且始终具有自己特定类型的VenuePart
s
以下是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
,而实际上它应该只有一个集合。我不能重写它,因为类型不同,对吗?当我运行报告时,我希望泛指类,在类中,我只是吐出Venue
s和VenuePart
s。但是,当我呈现表格之类的东西时,我想说得具体一点
我有很多这样的关系,我想知道我做错了什么。例如,我有一个订单
,它有订单项
s,但也有特定种类的订单
s,它有特定种类的订单项
s
更新:我应该注意,这些类是实体框架代码优先的实体。我希望这不重要,但我想可能会。我需要以代码优先能够正确创建表的方式构造类。这看起来不像代码首先可以处理泛型。很抱歉,此实施细节妨碍了优雅的解决方案:/
更新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>
{
}
公共抽象类VenuePart
{
公共抽象字符串名称描述符{get;}
}
公共类HoleVenuePart:VenuePart
{
公共字符串名称描述符{get{return“我是一个洞”;}
}
公共课堂场地T:VenuePart
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟公司公司{get;set;}
公共虚拟ICollection VenueParts{get;set;}
}
公共级高尔夫球场:场地
{
}
在这里,GolfCourseVenue拥有VenueParts集合,它可以包含HoleVenueParts或超级类HoleVenueParts。场馆的其他专业化将限制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
{
}
公共抽象类VenuePart
{
公共抽象字符串名称描述符{get;}
}
公共类HoleVenuePart:VenuePart
{
公共字符串名称描述符{get{return“我是一个洞”;}
}
公共课堂场地
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟公司公司{get;set;}
公共虚拟ICollection VenueParts{get;set;}
}
公共级高尔夫球场:场地
{
}
现在GolfCourseVenue拥有VenueParts集合,它可以包含VenueParts或超级类VenueParts。在这里,场馆的所有专业都可以包含任何类型的VenuePart,这些VenuePart可能合适,也可能不合适
在回答你关于协方差的评论时,我建议如下:
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
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); }
}
公共抽象类VenuePart
{
公共抽象字符串名称描述符{get;}
}
公共类HoleVenuePart:VenuePart
{
公共重写字符串名称描述符{get{return“I'm a hole”;}
}
公众抽象课堂场地
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共抽象ICollection VenueParts{get;}
}
公共级高尔夫球场:场地
{
私人ICollection_holeVenueParts;
公共高尔夫球场(I收集部分)
{
_holeVenueParts=零件;
}
公共覆盖ICollection VenueParts
{
得到
{
//这里我们需要防止客户端添加
//将新的VenuePart添加到VenueParts集合。
//他们必须使用Add(HoleVenuePart)。
//不幸的是,只有接口是协变的,而不是类型。
返回新的只读集合(
_holeVenueParts.OfType().ToList());
}
}
公共无效添加(HoleVenuePart){{u holeVenueParts.Add(part);}
}
您可以使用
公共抽象课堂场地
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟公司公司{get;set;}
公共虚拟IEnumerable VenueParts{get;set;}
}
公共级高尔夫球场:场地
{
公共字符串斜率{get;set;}
公共高尔夫球场()
{
List HoleVenueParts=新列表();
添加(新的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; }
}
如果您删除这两个集合的“set”部分,那么它将更有意义:基类提供“all parts”集合,而派生类除了基类1之外还具有筛选视图
注意:根据您的需要,使GolfVenue成为场馆
的专业化通用产品可能无法作为场馆
使用,并且场馆
将无法使用
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;}}
}
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; }
}
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() };