2014-10-20 209 views
3

我有一個數據庫,其中包含產品。 這些產品被分類,有類別子類別將枚舉映射到「子枚舉」

例如:

Product p1 = new Product() 
{ 
    Category = Category.Fruit, 
    Subcategory = Subcategory.Apple 
}; 

我的問題是,我要限制的子類別,根據不同的類別的事實。

下面的例子不應該是可能的:

Product p2 = new Product() 
{ 
    Category = Category.Fruit, 
    Subcategory = Subcategory.Cheese 
}; 

此外我想能夠返回一個字符串數組(每個類別匹配的枚舉),其各自具有相應的子類別的陣列。

我一直在想一段時間,但一無所獲,也沒有找到任何解決方案。

會有什麼建議?

+1

這裏沒有編譯時的方式,除非你使用的不同的子類別組獨立的枚舉做到這一點。有很多不同的方法可以在運行時進行驗證。 – 2014-10-20 18:04:51

+6

繼承層次結構可能更適合您的需求 – 2014-10-20 18:06:17

+0

這是業務邏輯,而不是純粹的技術解決方案。基本上,類別和子類別必須在某處(數據庫/代碼)進行定義,並且必須對其進行查找。 – 2014-10-20 18:06:37

回答

3

我喜歡地圖規則。 你也可以在你的枚舉值上加一個自定義屬性。

例如:

public enum Subcategory { 
    [SubcategoryOf(Category.Fruit)] 
    Apple, 
    [SubcategoryOf(Category.Dairy)] 
    Emmenthaler 
} 

這需要編寫一個SubcategoryOfAttribute類(參見here用於MS指南)。然後你可以編寫一個驗證器,它可以查看任何子類別並從中獲取合法的父類別。

在地圖上的優勢在於該關係在聲明中很好地闡述了出來。

缺點是每個子類別最多可以有一個父類別。

我覺得這很有趣,所以我把它取出來了。首先,屬性:

[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 
+0

非常感謝 - 這是我最終使用的是什麼。很棒! – JensOlsen112 2014-10-22 16:38:02

2

我的建議是有一個Dictionary<SubCategory, Category>,它將您的SubCategory映射到您的Category

之後,你可以擺脫Category對您的產品一起,或者你可以使用一個輔助方法

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

你所要做的就是代表一階邏輯(http://en.wikipedia.org/wiki/First-order_logic )使用枚舉。並與數據庫同步。在代碼中對它進行硬編碼時,這不是一件容易的事。已經提出了許多很好的解決方案。

就我而言,我只是使用字符串(或唯一標識符)的類別和子類別,並強制使用數據庫中定義的規則的完整性。但是如果你最終在代碼中使用它,它不會是編譯時。

Enum的問題是它必須與你的外部源和你的代碼相匹配。此外,它很難附加更多的信息,如價格或國家,或者即使你有不同種類的蘋果。