是否有奇怪的重复模板模式的替代品?

在过去的几周里,我以奇怪的重复模板模式给自己带来了一些麻烦。

继我的这两个问题之后:

  • 按值检索自定义枚举类的正确方法是什么?
  • 当第一次访问静态类是基类上的静态方法时,为什么我的静态对象没有被实例化?

如何改进以下示例:

public class DocketType : Enumeration { 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) { } } 

我想要一个静态方法,我不必在Enumeration类中重复:

 public abstract class Enumeration : IComparable where TEnum : Enumeration { protected Enumeration(X value, Y displayName) { AddToStaticCache(this); } public static TEnum Resolve(X value) { return Cache[value] as TEnum; } } 

正如您在第二个链接问题中看到的那样,问题在于对Enumeration.Resolve(X value);的调用Enumeration.Resolve(X value); 不会导致DocketType静态对象被实例化。

我并不反对完全从头开始重写。 我知道这是一个很大的代码味道。 目前,为了使这个工作,我的基类有受保护的静态方法ChildResolve ,我已经将Resolve添加到我的每个Enumeration类中。 讨厌的东西!

回答:

似乎没有很好的替代模式,所以我坚持使用模式并从接受的答案中获取灵感,并提出了这个:

 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; Cache.Add(locatedValue.Value, locatedValue); } } 

这也是在CodeCampServer MVC示例项目中使用的相同代码,因此我觉得使用它不那么脏!

它不是很优雅,但这样的事情可能会有所帮助:

 public class DocketType : Enumeration { 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 : IComparable where TEnum : Enumeration { private static readonly Dictionary _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(); } } 

您需要将静态字段推送到具有静态实例作为实例字段的类中。 这样,您可以通过单个静态成员访问枚举,该成员立即实例化所有枚举成员。

一个快速抛出的例子:

 // The Collection of values to be enumerated public class DocketEnum : EnumarationCollection { // 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 { // 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 where TType : EnumerationValue { // Resolve looks at the static Dictionary in the base helpers class public TType Resolve(X value) { return Cache[value] as TType; } public static Dictionary > Cache = new Dictionary>(); } // Base class for the value public abstract class EnumerationValue where TType : EnumerationValue { // helper constructer talks directly the the base helper class for the Enumeration protected EnumerationValue(X value, Y displayName) { EnumarationCollection.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()); } } 

你想对“给定类型的所有子类”做一些事情。 如果不使用AppDomain.Current.GetAssemblies()并迭代它们,任何这种性质都是不可能的。 如果采用这种方法,可以通过创建仅应用于程序集的程序集级别属性(以及应包含在子类搜索中的其他程序)来优化性能。并在准备调用时使用它.GetTypes()在每个集会上。

为了清楚起见,这是一个获取所有子类的示例:

 Type[] subclasses = AppDomain.CurrentDomain.GetAssemblies() .Where(x => Attribute.IsDefined(typeof(MyEnumeartionAssemblyAttribute))) .SelectMany(x => x.GetTypes()) .Where(x => x.BaseType != null && x.BaseType.IsGenericType && x.BaseType.GetGenericTypeDefinition() == typeof(Enumeration<,,>)); 

从那里开始,应该是在每个System.Type上使用reflection并使用静态字段执行操作的简单问题。

如果您确实想要强制运行另一个类的静态构造函数,则可以使用RuntimeHelpers.RunClassConstructor 。 您可以从Enumeration的静态构造函数中调用它Enumeration以便在第一次在generics类型的任何实例化上使用静态方法时运行它:

 static Enumeration() { RuntimeHelpers.RunClassConstructor(typeof(TEnum).TypeHandle); }