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 { ... } }
}