c# - 使用枚举类保持枚举到对象的映射?

标签 c# design-patterns enums mapping

我经常需要枚举和另一个对象(本例中为字符串)之间的全局硬编码映射。我想将枚举和映射定义放在一起以阐明维护。

如您所见,在此示例中,创建了一个带有一个静态字段的令人讨厌的类。

public enum EmailTemplates
{
    // Remember to edit the corresponding mapping singleton!
    WelcomeEmail,
    ConfirmEmail
}

public class KnownTemplates
{
    public static Dictionary<EmailTemplates, string> KnownTemplates;
    static KnownTemplates() {
        KnownTemplates.Add(EmailTemplates.WelcomeEmail, "File1.htm");
        KnownTemplates.Add(EmailTemplates.ConfirmEmail, "File2.htm");
    }
}

有时映射类可以有更多的功能和一个有意义的名字,映射事件甚至可以是私有(private)的。但这只会污染维护/关联问题。

有人对此有好的模式吗?

最佳答案

可以使用属性注解枚举,然后使用反射构建字典。

[AttributeUsage(AttributeTargets.Field)]
sealed class TemplateAttribute : Attribute {

  public TemplateAttribute(String fileName) {
    FileName = fileName;
  }

  public String FileName { get; set; }

}

enum EmailTemplate {

  [Template("File1.htm")]
  WelcomeEmail,

  [Template("File2.htm")]
  ConfirmEmail

}

class KnownTemplates {

  static Dictionary<EmailTemplate, String> knownTemplates;

  static KnownTemplates() {
    knownTemplates = typeof(EmailTemplates)
      .GetFields(BindingFlags.Static | BindingFlags.Public)
      .Where(fieldInfo => Attribute.IsDefined(fieldInfo, typeof(TemplateAttribute)))
      .Select(
        fieldInfo => new {
          Value = (EmailTemplate) fieldInfo.GetValue(null),
          Template = (TemplateAttribute) Attribute
            .GetCustomAttribute(fieldInfo, typeof(TemplateAttribute))
        }
      )
      .ToDictionary(x => x.Value, x => x.Template.FileName);
  }

}

如果你经常这样做,你可以创建一个更通用的通用函数,它将枚举值与与该枚举值关联的属性结合起来:

static IEnumerable<Tuple<TEnum, TAttribute>> GetEnumAttributes<TEnum, TAttribute>()
  where TEnum : struct
  where TAttribute : Attribute {
  return typeof(TEnum)
    .GetFields(BindingFlags.Static | BindingFlags.Public)
    .Where(fieldInfo => Attribute.IsDefined(fieldInfo, typeof(TAttribute)))
    .Select(
      fieldInfo => Tuple.Create(
        (TEnum) fieldInfo.GetValue(null),
        (TAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(TAttribute))
      )
    );
}

然后像这样使用它:

knownTemplates = GetEnumAttributes<EmailTemplate, TemplateAttribute>()
  .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2.FileName);

为了更有趣,您可以创建一个扩展方法:

static class EmailTemplateExtensions {

  static Dictionary<EmailTemplate, String> templates;

  static EmailTemplateExtensions() {
    templates = GetEnumAttributes<EmailTemplate, TemplateAttribute>()
      .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2.FileName);
  }

  public static String FileName(this EmailTemplate emailTemplate) {
    String fileName;
    if (templates.TryGetValue(emailTemplate, out fileName))
      return fileName;
    throw new ArgumentException(
      String.Format("No template defined for EmailTemplate.{0}.", emailTemplate)
    );
  }

}

然后调用 EmailTemplate.ConfirmEmail.FileName() 将返回 File2.htm

关于c# - 使用枚举类保持枚举到对象的映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10307459/

相关文章:

c# - 如何使用 MainMenu 在状态栏上显示与菜单项相关的文本?

c# - 网页中的二维码阅读器

swift - 如何创建一个返回整数元组的枚举函数?

c# - 在单元测试中设置 HttpContext.Current.Session

c# - 如何使用带有 ssl 的证书通过 https ://连接到 web 服务

c - C 语言的设计原理 DRY?

c# - 如何为一个列表中的不同类型的值设计工厂模式?

java - 几个枚举如何扩展一个包含用于 Java 中这些枚举的方法的类?

java - 使用枚举的单例

带有构造函数的 C++ 枚举类