C# 将枚举映射到";“子枚举”;

C# 将枚举映射到";“子枚举”;,c#,.net,enums,C#,.net,Enums,我有一个包含产品的数据库。 这些产品分类为类别和子类别 例如: Product p1 = new Product() { Category = Category.Fruit, Subcategory = Subcategory.Apple }; public enum Subcategory { [SubcategoryOf(Category.Fruit)] Apple, [SubcategoryOf(Category.Dairy)] E

我有一个包含产品的数据库。 这些产品分类为类别子类别

例如:

Product p1 = new Product()
{ 
    Category = Category.Fruit, 
    Subcategory = Subcategory.Apple 
 };
public enum Subcategory {
    [SubcategoryOf(Category.Fruit)]
    Apple,
    [SubcategoryOf(Category.Dairy)]
    Emmenthaler
}
我的问题是,我想根据类别限制子类别

以下示例不可能出现:

Product p2 = new Product()
{ 
    Category = Category.Fruit, 
    Subcategory = Subcategory.Cheese 
};
此外,我希望能够返回一个字符串数组(匹配每个类别枚举),每个字符串都有一个对应子类别的数组

我已经思考了一段时间,但什么也没想到,也没有在网上找到任何解决方案


有什么建议?

我的建议是有一本
字典,它将你的
子类别映射到你的
类别

在这之后,您可以将产品上的
类别一起去掉,也可以使用helper方法

public class Product
{
    static Dictionary<SubCategory, Category> _categoriesMap;

    public static Product()
    {
        _categoriesMap = new Dictionary<SubCategory, Category>();
        _categoriesMap.Add(SubCategory.Apple, Category.Fruit);
    }

    public SubCategory SubCategory { get; set; }

    public Category Category
    {
        get { return _categoriesMap[this.SubCategory]; }
    }
}
公共类产品
{
静态字典(categoriesMap);;
公共静态产品()
{
_categoriesMap=newdictionary();
_categoriesMap.Add(SubCategory.Apple,Category.Fruit);
}
公共子类别子类别{get;set;}
公共类别
{
获取{return _categoriesMap[this.SubCategory];}
}
}

您试图做的是使用枚举表示一阶逻辑()。以及与数据库同步。当用代码硬编码时,这不是一项容易的任务。已经提出了许多好的解决办法

就我而言,我将只为Category和SubCategory使用字符串(或唯一ID),并使用数据库中定义的规则强制实现完整性。但如果您最终在代码中使用它,就不会是编译时了

Enum的问题在于它必须与外部源代码和代码匹配。而且,如果你有不同种类的苹果,你也很难在上面附加更多的信息,比如价格、国家或其他信息。

我喜欢地图规则。 还可以在枚举值上添加自定义属性

例如:

Product p1 = new Product()
{ 
    Category = Category.Fruit, 
    Subcategory = Subcategory.Apple 
 };
public enum Subcategory {
    [SubcategoryOf(Category.Fruit)]
    Apple,
    [SubcategoryOf(Category.Dairy)]
    Emmenthaler
}
这要求您编写一个
属性子类别
类(有关MS指南,请参阅)。然后,您可以编写一个验证器,它可以查看任何子类别,并从中获取合法的父类别

与map相比,这种方法的优点是在声明中很好地阐述了这种关系

缺点是每个子类别最多只能有一个父类别

我发现这很有趣,所以我把它删掉了。首先是属性:

[AttributeUsage(AttributeTargets.Field)]
public class SubcategoryOf : Attribute {
    public SubcategoryOf(Category cat) {
        Category = cat;
    }
    public Category Category { get; private set; }
}
然后我们制作一些模拟枚举

public enum Category {
    Fruit,
    Dairy,
    Vegetable,
    Electronics
}

public enum Subcategory {
    [SubcategoryOf(Category.Fruit)]
    Apple,
    [SubcategoryOf(Category.Dairy)]
    Buttermilk,
    [SubcategoryOf(Category.Dairy)]
    Emmenthaler,
    [SubcategoryOf(Category.Fruit)]
    Orange,
    [SubcategoryOf(Category.Electronics)]
    Mp3Player
}
现在我们需要一个谓词来确定子类别是否与类别匹配(注意:如果需要,您可以有多个父类别-您需要修改属性和该谓词以获取所有属性并检查每个属性)

public static class Extensions {
    public static bool IsSubcategoryOf(this Subcategory sub, Category cat) {
        Type t = typeof(Subcategory);
        MemberInfo mi = t.GetMember(sub.ToString()).FirstOrDefault(m => m.GetCustomAttribute(typeof(SubcategoryOf)) != null);
        if (mi == null) throw new ArgumentException("Subcategory " + sub + " has no category.");
        SubcategoryOf subAttr = (SubcategoryOf)mi.GetCustomAttribute(typeof(SubcategoryOf));
        return subAttr.Category == cat;
    }
}
然后输入产品类型进行测试:

public class Product {
    public Product(Category cat, Subcategory sub) {
        if (!sub.IsSubcategoryOf(cat)) throw new ArgumentException(
            String.Format("{0} is not a sub category of {1}.", sub, cat), "sub");
        Category = cat;
        Subcategory = sub;
    }

    public Category Category { get; private set; }
    public Subcategory Subcategory { get; private set; }
}
测试代码:

Product p = new Product(Category.Electronics, Subcategory.Mp3Player); // succeeds
Product q = new Product(Category.Dairy, Subcategory.Apple); // throws an exception

除非对不同的子类别组使用单独的枚举,否则没有编译时方法可以做到这一点。可以在运行时使用许多不同的方法进行验证。继承层次结构可能更适合您的要求这是业务逻辑,而不是纯技术解决方案。基本上,类别与子类别之间的关系必须在某个地方定义(数据库/代码),并且必须对其进行查找。让产品由每个类别实现一个抽象类这很难,但如果您赶时间,可以将类别和子类别连接到一个枚举中:
enum Cats{Fruit_Apple,Fruit_Pear}
非常感谢-这就是我最终使用的。效果非常好!