2012-04-24 10 views
11

मुझे अक्सर एक enum और अन्य ऑब्जेक्ट (इस उदाहरण में एक स्ट्रिंग) के बीच एक वैश्विक हार्ड-कोडित मैपिंग की आवश्यकता होती है। मैं रखरखाव को स्पष्ट करने के लिए enum और मैपिंग परिभाषाओं का सह-पता लगाना चाहता हूं।enum class के साथ enum-to-object मैपिंग रखें?

आप देख सकते हैं, इस उदाहरण में, एक स्थिर क्षेत्र के साथ एक कष्टप्रद वर्ग बनाया जाता है।

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

कभी-कभी मानचित्रण वर्ग में अधिक कार्य और सार्थक नाम हो सकता है, और मैपिंग गतिविधि भी निजी हो सकती है। लेकिन यह केवल रखरखाव/सहसंबंध समस्या को प्रदूषित करता है।

किसी के पास इसके लिए एक अच्छा पैटर्न है?

उत्तर

6

आप गणन व्याख्या और फिर प्रतिबिंब का उपयोग शब्दकोश का निर्माण करने के लिए विशेषताओं का उपयोग कर सकते हैं।

[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 वापस आ जाएगा।

+0

मुझे लगता है कि वे 'स्ट्रिंग sFile = ईमेल टेम्पलेट। कॉन्फर्म। टेम्पलेटफाइल' जैसे वाक्यविन्यास के साथ कक्षा के उपयोग को हटाना चाहते हैं। – AMissico

+0

मार्टिन! धन्यवाद! गुण मेरी अधिकांश स्थितियों (जहां एक स्ट्रिंग उचित है) के लिए एक अच्छा समाधान है। मुझे पता है कि मेरे पास ऐसे मामले हैं जहां प्रत्येक enum में एक जटिल वस्तु मैप की जाती है, लेकिन यह कुछ स्केलर भी कवर कर सकती है। – shannon

+0

यह और अधिक भयानक हो जाता है जितना मैं इसका उपयोग करता हूं। फिर मार्टिन धन्यवाद। – shannon

2

आम तौर पर, जब आप अपने enum तत्वों को अतिरिक्त जानकारी या व्यवहार जोड़ना चाहते हैं, तो इसका मतलब है कि आपको इसके बजाय एक पूर्ण उड़ा वर्ग की आवश्यकता है। आप से (old-) जावा प्रकार सुरक्षित enum पैटर्न उधार लेते हैं और कुछ इस तरह बना सकते हैं:

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) { ... } 
} 

अब आप Location और Render ऊपर की तरह अपने तत्वों के लिए किसी भी गुण या तरीकों संबद्ध कर सकते हैं,।

+0

धन्यवाद, एक बहुत अच्छी रणनीति भी। स्पेक्ट्रम के दूसरे छोर पर अंतर भरता है। – shannon

2

यहां एक ऐसा दृष्टिकोण है जो मेरे लिए बहुत अच्छा काम करता है।

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 
} 

अब आप प्रतिबिंब का उपयोग कर सकते BaseErrWarn वर्ग के लिए Enum मैप करने के लिए:

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

यहाँ एक उदाहरण है जो एक वस्तु के लिए एक Enum नक्शा और फिर इसे बंद क्षेत्रों को खींचने के लिए इस मानचित्रण का उपयोग करता है :

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

अच्छा दृष्टिकोण आपके गुणों पर अधिक बारीक नियंत्रण है और प्रतिबिंब> मैपिंग> मानव-पठनीय-रूप के संदर्भ में कम यात्रा करने के लिए। –

संबंधित मुद्दे