Is there an alternative to the Curiously Recurring Template Pattern?
在过去的几周里,我用奇怪的重复模板模式给自己带来了一些头痛。
以下是我的两个问题:
- 正确的检索方法是什么我的自定义枚举类它们的价值?
- 为什么我的静态物体不是当首次访问静态类是上的静态方法基类?
如何改进以下示例:
1 2 3 4 5 6 7 8 | public class DocketType : Enumeration<DocketType, int, string> { public static DocketType Withdrawal = new DocketType(2,"Withdrawal"); public static DocketType Installation = new DocketType(3,"Installation"); private DocketType(int docketTypeId, string description) : base(docketTypeId, description) { } } |
我想要一个静态方法,不必在
1 2 3 4 5 6 7 8 9 10 11 12 | public abstract class Enumeration<TEnum, X, Y> : IComparable where TEnum : Enumeration<TEnum, X, Y> { protected Enumeration(X value, Y displayName) { AddToStaticCache(this); } public static TEnum Resolve(X value) { return Cache[value] as TEnum; } } |
从我的第二个链接问题可以看出,这个问题的问题是,对
我并不反对从头重写这个。我知道这是一种大代码味道。目前,为了实现这一点,我的基类使用了受保护的静态方法
答:
似乎没有什么好的模式可供选择,所以我坚持这个模式,从公认的答案中获得灵感,并提出了这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | static Enumeration() { GetAll(); } public static void GetAll() { var type = typeof(TEnum); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); foreach (var info in fields) { var locatedValue = info.GetValue(null) as Enumeration<TEnum, X, Y>; Cache.Add(locatedValue.Value, locatedValue); } } |
这也是在codecampserver mvc示例项目中使用的相同代码,因此使用它时我感觉不太脏!
它不太优雅,但像这样的东西可能会起作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | public class DocketType : Enumeration<DocketType, int, string> { public static readonly DocketType Withdrawal = new DocketType(2,"Withdrawal"); public static readonly DocketType Installation = new DocketType(3,"Installation"); private DocketType(int docketTypeId, string description) : base(docketTypeId, description) { } } public abstract class Enumeration<TEnum, TId, TDescription> : IComparable where TEnum : Enumeration<TEnum, TId, TDescription> { private static readonly Dictionary<TId, TEnum> _cache; static Enumeration() { Type t = typeof(TEnum); _cache = t.GetFields(BindingFlags.Public | BindingFlags.Static) .Where(f => f.FieldType == t) .Select(f => (TEnum)f.GetValue(null)) .ToDictionary(e => e.Id, e => e); } public static TEnum Resolve(TId id) { return _cache[id]; } public TId Id { get; private set; } public TDescription Description { get; private set; } protected Enumeration(TId id, TDescription description) { Id = id; Description = description; } // IComparable public int CompareTo(object obj) { // TODO throw new NotImplementedException(); } } |
您需要将静态字段推送到一个类中,该类将静态实例作为实例字段。这样,您就可以通过一个静态成员访问枚举,该静态成员立即引用所有枚举成员。
一个快速组合的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | // The Collection of values to be enumerated public class DocketEnum : EnumarationCollection<DocketType, int, string> { // Values are fields on a statically instanced version of this class public DocketType Withdrawal = new DocketType(2,"Withdrawal"); public DocketType Installation = new DocketType(3,"Installation"); // The publicly accessible static enumeration public static DocketEnum Values = new DocketEnum(); } // The actual value class public class DocketType : EnumerationValue<DocketType, int, string> { // Call through to the helper base constructor public DocketType(int docketTypeId, string description) : base(docketTypeId, description) { } } // Base class for the enumeration public abstract class EnumarationCollection<TType, X, Y> where TType : EnumerationValue<TType, X, Y> { // Resolve looks at the static Dictionary in the base helpers class public TType Resolve(X value) { return Cache[value] as TType; } public static Dictionary<X, EnumerationValue<TType, X, Y> > Cache = new Dictionary<X, EnumerationValue<TType, X, Y>>(); } // Base class for the value public abstract class EnumerationValue<TType, X, Y> where TType : EnumerationValue<TType, X, Y> { // helper constructer talks directly the the base helper class for the Enumeration protected EnumerationValue(X value, Y displayName) { EnumarationCollection<TType, X,Y >.Cache.Add(value, this as TType); } } class MainClass { public static void Main (string[] args) { // You can immediately resolve to the enumeration Console.WriteLine(DocketEnum.Values.Resolve(2).ToString()); } } |
如果确实要强制另一个类的静态构造函数运行,则可以使用RuntimeHelpers.RunClassConstructor。您可以从
1 2 3 4 |
您需要对"给定类型的所有子类"执行一些操作。如果不使用appdomain.current.getassembles()并对其进行迭代,任何此类性质的操作都是不可能的。如果采用这种方法,则可以通过创建仅应用于程序集(以及应包含在子类搜索中的其他属性)的程序集级属性来优化性能,并在准备对每个程序集调用.gettypes()时使用该属性。
很明显,下面是一个获得所有这些子类的示例:
1 2 3 4 5 6 |
从这里开始,在每个系统上使用反射应该是一个简单的问题,输入静态字段并做您想做的事情。