C# 基类枚举在派生类中以不同方式实现
我的设想:C# 基类枚举在派生类中以不同方式实现,c#,inheritance,enums,C#,Inheritance,Enums,我的设想: public class EntityBase { public int ID { get; set; } [Required()] public string Name { get; set; } //And this is what is getting me //I want a "Type" enum } 然后派生类将有不同的枚举,它们将分配给类型 public class AnimalEntity : EntityBase {
public class EntityBase
{
public int ID { get; set; }
[Required()]
public string Name { get; set; }
//And this is what is getting me
//I want a "Type" enum
}
然后派生类将有不同的枚举,它们将分配给类型
public class AnimalEntity : EntityBase
{
//Type would have an 'animal type' value: Land, Sea or Air
//Implementation code would do something like:
// myAnimal.Type = AnimalType.Land
}
public class PersonEntity : EntityBase
{
//Type would have a 'person type' value: Doctor, Lawyer or Engineer
//Implementation code would do something like:
// myPerson.Type = PersonType.Lawyer
}
public class MonsterEntity : EntityBase
{
//Type would have a 'monster type' value: Goblinoid, Undead
}
所以,最大的问题是我想做什么,对吗?我正在尝试创建一个基本存储库类,它将返回按类型分组的实体。我所有的实体都有某种类型的“类型”,我想创建一个通用的“类型分组”
公共抽象类RepositoryBase:IRepositoryBase其中T:EntityBase
{
//我们的通用GetAsync、GetByIdAsync和所有其他CRUD
//然后像这样:
公共IEnumerable GetGroupedByType(字符串搜索项)
{
var实体=
从DbSet中的s
其中(searchTerm==null | | s.Name.ToLower().Contains(searchTerm))
将s按s分组。键入g
选择newgroupeddata{Key=g.Key.ToString(),Data=g};
返回(实体);
}
}
当T是动物性时,我会得到相应实体的陆地、海洋和空气。就个人而言,我会找医生、律师、工程师团队
如果我的方法/设计无效或不理想,请告诉我。我可以想到两个选项: 首先,最好使用(
T
,在本示例中):
Enum(请原谅)属于二等公民,所以您可能首先想到的是,它将不起作用:
class EntityBase<T> where T : enum {
public T Type { get; set; }
}
在EntityTypeBase
中实现您需要熟悉的一切(=
和!=
运算符、IConvertible
界面和其他样板文件)。这需要大量代码,您还需要在EF中管理这些代码(否则,除非您将内存中的所有内容作为对象加载,否则您将无法在查询中使用此类属性)。您也可以(通过运行时检查)但这将中断EF中的SQL代码生成
在这种情况下,我建议使用EF knows和understand类型。您可以使用字符串(如果愿意)或整数(如本例所示):
在派生类中:
class AnimalEntity : EntityBase {
public override int Type {
get { return base.Type; }
set {
if (!Enum.IsDefined(typeof(AnimalType), value))
throw new ArgumentException();
base.Type = (int)value;
}
}
}
这样,您仍然可以使用PersonType.Layer
和AnimalType.Land
保持一些类型安全性。当然,您需要保持枚举同步,以避免重复值(否则,groupby
将不起作用)
最后,请考虑使用另一个实体。如果您有另一个表EntityType
:
ID Name ApplicableTo
0 Laywer Person
1 Programmer Person
2 Land Animal
...
在我看来,这比硬编码常量更安全(因为完整性是由DB引擎本身授予的)。当然,在
EntityType
表中进行搜索所要付出的代价是额外的开销(除非您使用某种缓存机制)。在泛型中指定枚举有什么不对<代码>实体库等等。老实说,我不确定自己会选择这样做,但这仍然是可能的。也就是说,我不知道你会如何将其整合到分组中。我个人不会基于尝试提供通用代码来设计样式。我只需要设计一些东西,然后确定公共逻辑所在的位置。例如,与其更改枚举,为什么不让每个派生存储库实现分组功能?@AdamHouldsworth除非我弄错了,否则目标似乎是将派生类的类型化枚举作为键。杰森,你能证实这一点吗?@Adamhuldsworth-我开始接受你的想法。尝试按类型抽象组可能不足以满足所有其他要求。谢谢。@Patrickhoffman是的,它并不总是有用的,但有时我想看看它!是的,反正是+1。这不是你的错;)@PatrickHofman LOL我们应该为此责备Eric(事实上我想知道他是否写过关于“我们将如何使用泛型以及为什么我们不能使用泛型”的文章)。其中t:enum-不起作用。是的。。。然后,但这将中断EF中的SQL代码生成。你涵盖了我一直在头痛的所有基础和痛点。谢谢您的反馈。@Jason是的,不幸的是在中T:U
(其中U
不是像default
、class
、new
或struct
)这样的特例,它必须是基类或接口。值类型(然后enum
)将退出游戏。实际上,您可以使用一个基类并编写一些代码来指示EF使用它,但是…它值吗?顺便说一下,用帕特里克建议的字符串,你的生活更简单(当然要支付的代价是DB开销和更大的运行时间检查),所以你也可以考虑使用它们。谢谢你的反馈。我曾想过这些,但希望能有更干净的东西。
public class EntityBase
{
public string Type {get;set;}
}
public static class AnimalTypes
{
public const string Dog = "dog";
public const string Cat = "cat";
}
class EntityBase<T> where T : enum {
public T Type { get; set; }
}
class EntityBase<T> where T : EntityTypeBase {
public T Type { get; set; }
}
class EntityBase
public virtual int Type { get; set; }
}
class AnimalEntity : EntityBase {
public override int Type {
get { return base.Type; }
set {
if (!Enum.IsDefined(typeof(AnimalType), value))
throw new ArgumentException();
base.Type = (int)value;
}
}
}
ID Name ApplicableTo
0 Laywer Person
1 Programmer Person
2 Land Animal
...
public static class PersonType {
public static EntityType Lawyer { get { ... } }
public static EntityType Programmer { get { ... } }
}