基类枚举在派生类中实现不同

时间:2014-10-27 15:49:17

标签: 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
}

然后派生类将具有不同的枚举,它们将分配给Type。

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 
}

所以,最重要的问题是我想做什么,对吧?我正在尝试创建一个基本存储库类,它将返回按类型分组的实体。我的所有实体都会有某种“类型”,我想创建一个通用的“按类型分组”。

public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : EntityBase
{
     //Our common GetAsync, GetByIdAsync, and all our other CRUD

     //And then something like this:
    public IEnumerable<GroupedData<string, T>> GetGroupedByType(string searchTerm)
    {
        var entities =
            from s in DbSet
            where (searchTerm == null || s.Name.ToLower().Contains(searchTerm))
            group s by s.Type into g
            select new GroupedData<string, T> { Key = g.Key.ToString(), Data = g };

        return (entities);
    }
}

当T是AnimalEntity时,我会使用相应的实体获得Land,Sea和Air组。对于PersonEntity,我会找到Doctor,Lawyer,Engineer团队。

如果我的方法/设计无效或不理想,请告诉我。

2 个答案:

答案 0 :(得分:1)

我能想到的两个选择:

首先,最好在此示例中使用generic type parameterT):

public class EntityBase<T>
{
   public T Type {get;set;}
}

在类型声明中提供该类型:

public class AnimalEntity : EntityBase<AnimalEnum>
{ }

其次,如果您需要更多自由,我通常会使用string个符号列表:

public class EntityBase
{
   public string Type {get;set;}
}

public static class AnimalTypes
{
    public const string Dog = "dog";
    public const string Cat = "cat";
}

答案 1 :(得分:1)

Enum(请原谅我)是一类二等公民,所以你可能会想到的第一件事就是不能工作

class EntityBase<T> where T : enum {
    public T Type { get; set; }
}

不幸的是它没有编译,你可以考虑用基类替换enum

class EntityBase<T> where T : EntityTypeBase {
    public T Type { get; set; }
}

EntityTypeBase中实现您需要的所有内容(==!=运算符,IConvertible接口和其他样板文件)。它是很多代码,您还需要在EF中管理它(否则您将无法在查询中使用此类属性,除非您将内存中的所有内容作为对象加载)。您也可以force the use of enums(使用运行时检查)但这会破坏EF中的SQL代码生成。

我建议在这种情况下是使用EF知道和理解的类型。您可以使用字符串(如果您愿意)或整数(如本例所示):

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;
        }
    }
}

通过这种方式,您仍然可以使用PersonType.LayerAnimalType.Land保持一点类型安全性。当然,你需要保持你的枚举同步,没有重复的值(否则group by不会工作)。

最后请也考虑使用......另一个实体。如果您有另一张表EntityType

ID    Name          ApplicableTo
0     Laywer        Person
1     Programmer    Person
2     Land          Animal
...

你在setter中要做的是检查类型是否适用,你可能没有几个便利类可以按类型对它们进行分组:

public static class PersonType {
    public static EntityType Lawyer { get { ... } }
    public static EntityType Programmer { get { ... } }
}

IMO 规模更好(更容易添加新项目,您可以将某些行为委托给EntityType个项目)和更安全比硬编码常量(因为完整性由DB引擎本身授予)。当然,支付价格是EntityType表中搜索的额外开销(除非你使用一些缓存机制)。