2012-04-24 42 views
11

Tôi thường xuyên cần một ánh xạ mã hóa toàn cục giữa một enum và một đối tượng khác (một chuỗi trong ví dụ này). Tôi muốn đồng định vị trí các định nghĩa enum và ánh xạ để làm rõ việc bảo trì.Giữ bản đồ enum-to-object với lớp enum?

Như bạn có thể thấy, trong ví dụ này, một lớp gây phiền nhiễu với một trường tĩnh được tạo.

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"); 
    } 
} 

Đôi khi lớp ánh xạ có thể có nhiều chức năng hơn và tên có ý nghĩa và hoạt động lập bản đồ thậm chí có thể riêng tư. Nhưng điều đó chỉ gây ô nhiễm vấn đề bảo trì/tương quan.

Bất kỳ ai có mô hình tốt về điều này?

Trả lời

6

Bạn có thể sử dụng các thuộc tính để chú thích điều tra và sau đó sử dụng phản chiếu để tạo từ điển.

[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); 
    } 

} 

Nếu bạn làm điều này rất nhiều bạn có thể tạo một hàm tổng quát tổng quát hơn kết hợp các giá trị liệt kê với một thuộc tính gắn liền với giá trị liệt kê:

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)) 
    ) 
    ); 
} 

Và sử dụng nó như thế này:

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

Để có nhiều niềm vui hơn, bạn có thể tạo phương thức mở rộng:

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) 
    ); 
    } 

} 

Sau đó, gọi EmailTemplate.ConfirmEmail.FileName() sẽ trả lại File2.htm.

+0

Tôi nghĩ rằng họ muốn loại bỏ việc sử dụng lớp học, với cú pháp như 'string sFile = EmailTemplate.Confirm.TemplateFile;'. – AMissico

+0

Martin! Cảm ơn bạn! Thuộc tính là một giải pháp tuyệt vời cho hầu hết các tình huống của tôi (những nơi có chuỗi thích hợp). Tôi biết tôi có trường hợp một đối tượng phức tạp được ánh xạ tới mỗi enum, nhưng điều này thậm chí có thể bao gồm một vài scalars là tốt. – shannon

+0

Điều này trở nên tuyệt vời hơn khi tôi sử dụng nó. Cảm ơn Martin lần nữa. – shannon

2

Thông thường, khi bạn muốn thêm thông tin hoặc hành vi bổ sung vào các yếu tố enum của bạn, điều đó có nghĩa là bạn cần một lớp thổi đầy đủ thay thế. Bạn có thể vay từ (old-) Java loại an toàn enum mô hình và tạo ra một cái gì đó như thế này:

sealed class EmailTemplate { 
    public static readonly EmailTemplate Welcome = new EmailTemplate("File1.html"); 
    public static readonly EmailTemplate Confirm = new EmailTemplate("File2.html"); 

    private EmailTemplate(string location) { 
    Location = location; 
    } 
    public string Location { get; private set; } 

    public string Render(Model data) { ... } 
} 

Bây giờ bạn có thể kết hợp bất kỳ thuộc tính hoặc các phương pháp để các yếu tố của bạn, giống như LocationRender trên.

+0

Cảm ơn bạn, cũng là một chiến lược rất hay. Điền vào khoảng trống ở đầu kia của quang phổ. – shannon

2

Đây là cách tiếp cận hoạt động khá tốt đối với tôi.

public class BaseErrWarn : Attribute 
{ 
    public string Code { get; set; } 
    public string Description { get; set; } 

    public BaseErrWarn(string code, string description) 
    { 
     this.Code = code; 
     this.Description = description; 
    } 
} 

public enum ErrorCode 
{ 
    [BaseErrWarn("ClientErrMissingOrEmptyField", "Field was missing or empty.")] ClientErrMissingOrEmptyField, 
    [BaseErrWarn("ClientErrInvalidFieldValue", "Not a valid field value.")] ClientErrInvalidFieldValue, 
    [BaseErrWarn("ClientErrMissingValue", "No value passed in.")] ClientErrMissingValue 
} 

Bây giờ bạn có thể sử dụng phản ánh để lập bản đồ Enum đến lớp BaseErrWarn:

public static BaseErrWarn GetAttribute(Enum enumVal) 
{ 
    return (BaseErrWarn)Attribute.GetCustomAttribute(ForValue(enumVal), typeof(BaseErrWarn)); 
} 

private static MemberInfo ForValue(Enum errorEnum) 
{ 
    return typeof(BaseErrWarn).GetField(Enum.GetName(typeof(BaseErrWarn), errorEnum)); 
} 

Dưới đây là một ví dụ trong đó sử dụng bản đồ này để lập bản đồ một Enum để một đối tượng và sau đó kéo các lĩnh vực tắt của nó :

public BaseError(Enum errorCode) 
    { 
     BaseErrWarn baseError = GetAttribute(errorCode); 
     this.Code = baseError.Code; 
     this.Description = baseError.Description; 
    } 

    public BaseError(Enum errorCode, string fieldName) 
    { 
     BaseErrWarn baseError = GetAttribute(errorCode); 
     this.Code = baseError.Code; 
     this.Description = baseError.Description; 
     this.FieldName = fieldName; 
    } 
+0

Cách tiếp cận tốt đẹp mà bạn có quyền kiểm soát chi tiết hơn đối với các thuộc tính và ít đi du lịch hơn để thực hiện dưới dạng phản ánh> ánh xạ> biểu mẫu có thể đọc được. –

Các vấn đề liên quan