2013-10-22 5 views
6

मेरे आवेदन में मुझे रनटाइम के दौरान गुण बनाने/हटाने के लिए ExpandoObject का उपयोग करना होगा; हालांकि, मुझे किसी फंक्शन के लौटे ExpandoObject को संबंधित ऑब्जेक्ट/क्लास में मैप करना होगा।रिकर्सिवली मैपिंग ExpandoObject

  1. के रूप में माना जाता यह रिकर्सिवली ExpandoObject के भीतर वस्तुओं को मैप नहीं है: तो मैं एक छोटे से मैपर कि काम करता है के साथ लेकिन 3 समस्याओं के साथ आया है।
  2. जब मैं int को nullable में मैप करने का प्रयास करता हूं तो यह एक प्रकार मेल नहीं खाएगा क्योंकि मुझे इसका पता लगाने और सही तरीके से कास्ट करने का कोई तरीका नहीं मिल रहा है।
  3. फ़ील्ड्स को public string Property; मैप नहीं किया जा सकता है।

कोड:

I- कार्यान्वयन:

public static class Mapper<T> where T : class 
{ 
    #region Properties 

    private static readonly Dictionary<string, PropertyInfo> PropertyMap; 

    #endregion 

    #region Ctor 

    static Mapper() { PropertyMap = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToDictionary(p => p.Name.ToLower(), p => p); } 

    #endregion 

    #region Methods 

    public static void Map(ExpandoObject source, T destination) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 
     if (destination == null) 
      throw new ArgumentNullException("destination"); 

     foreach (var kv in source) 
     { 
      PropertyInfo p; 
      if (PropertyMap.TryGetValue(kv.Key.ToLower(), out p)) 
      { 
       Type propType = p.PropertyType; 
       if (kv.Value == null) 
       { 
        if (!propType.IsByRef && propType.Name != "Nullable`1") 
        { 
         throw new ArgumentException("not nullable"); 
        } 
       } 
       else if (kv.Value.GetType() != propType) 
       { 
        throw new ArgumentException("type mismatch"); 
       } 
       p.SetValue(destination, kv.Value, null); 
      } 
     } 
    } 

    #endregion 
} 

द्वितीय: उपयोग:

public static void Main() 
{ 
    Class c = new Class(); 
    dynamic o = new ExpandoObject(); 
    o.Name = "Carl"; 
    o.Level = 7; 
    o.Inner = new InnerClass 
       { 
         Name = "Inner Carl", 
         Level = 10 
       }; 

    Mapper<Class>.Map(o, c); 

    Console.Read(); 
} 

internal class Class 
{ 
    public string Name { get; set; } 
    public int? Level { get; set; } 
    public InnerClass Inner { get; set; } 
    public string Property; 
} 

internal class InnerClass 
{ 
    public string Name { get; set; } 
    public int? Level { get; set; } 
} 
+0

किसी भी सवाल का जवाब ... –

उत्तर

4

3- यदि संपत्ति इस public string Property; की तरह बनाई गई है तो गुण प्राप्त नहीं करते हैं।

ओह, यह एक संपत्ति नहीं है, यह एक क्षेत्र है। यदि आप फ़ील्ड पर भी विचार करना चाहते हैं।

static Mapper() 
{ 
    PropertyMap = typeof(T).GetProperties(BindingFlags.Public | 
               BindingFlags.NonPublic | 
               BindingFlags.Instance) 
               .ToDictionary(p => p.Name.ToLower(), p => p); 

    FieldMap = typeof(T).GetFields(BindingFlags.Public | 
               BindingFlags.NonPublic | 
               BindingFlags.Instance) 
               .ToDictionary(f => f.Name.ToLower(), f => f); 
} 

2- जब मैं एक Nullable को पूर्णांक मैप करने के लिए बस इसे एक प्रकार मेल नहीं खाता फेंक देते हैं क्योंकि मैं का पता लगाने और इसे ठीक से कास्ट करने के लिए एक तरह से नहीं मिल सकता है की कोशिश करो।

Nullable प्रकार की जांच क्यों करें, प्रतिबिंब इसे समझने दें। यदि मान वैध है, तो इसे असाइन किया जाएगा।

public static void Map(ExpandoObject source, T destination) 
{ 
    if (source == null) 
     throw new ArgumentNullException("source"); 
    if (destination == null) 
     throw new ArgumentNullException("destination"); 

    foreach (var kv in source) 
    { 
     PropertyInfo p; 
     if (PropertyMap.TryGetValue(kv.Key.ToLower(), out p)) 
     { 
      p.SetValue(destination, kv.Value, null); 
     } 
     else 
     { 
      FieldInfo f; 
      if (FieldMap.TryGetValue(kv.Key.ToLower(), out f)) 
      { 
       f.SetValue(destination, kv.Value); 
      } 
     } 
    } 
} 

1 - के रूप में माना जाता यह रिकर्सिवली ExpandoObject के भीतर वस्तुओं को मैप नहीं है।

कम से कम आपके InnerClass के लिए काम करने लगता है।

Class c = new Class(); 
dynamic o = new ExpandoObject(); 
o.Name = "Carl"; 
o.Level = 7; 
o.Inner = new InnerClass 
{ 
    Name = "Inner Carl", 
    Level = 10 
}; 

o.Property = "my Property value"; // dont forget to set this 

Mapper<Class>.Map(o, c); 

संपादित: अपनी टिप्पणी के आधार पर, मैं दो अतिभारित तरीकों MergeProperty बनाने है। आप खेतों के लिए समान अधिभारित विधियां लिख सकते हैं। ?

public static void MergeProperty(PropertyInfo pi, ExpandoObject source, object target) 
{ 
    Type propType = pi.PropertyType; 

    // dont recurse for value type, Nullable<T> and strings 
    if (propType.IsValueType || propType == typeof(string)) 
    { 
     var sourceVal = source.First(kvp => kvp.Key == pi.Name).Value; 
     if(sourceVal != null) 
      pi.SetValue(target, sourceVal, null); 
    } 
    else // recursively map inner class properties 
    { 
     var props = propType.GetProperties(BindingFlags.Public | 
                BindingFlags.NonPublic | 
                BindingFlags.Instance); 

     foreach (var p in props) 
     { 
      var sourcePropValue = source.First(kvp => kvp.Key == pi.Name).Value; 
      var targetPropValue = pi.GetValue(target, null); 

      if (sourcePropValue != null) 
      { 
       if (targetPropValue == null) // replace 
       { 
        pi.SetValue(target, source.First(kvp => kvp.Key == pi.Name).Value, null); 
       } 
       else 
       { 
        MergeProperty(p, sourcePropValue, targetPropValue); 
       } 
      } 
     } 

    } 
} 

public static void MergeProperty(PropertyInfo pi, object source, object target) 
{ 
    Type propType = pi.PropertyType; 
    PropertyInfo sourcePi = source.GetType().GetProperty(pi.Name); 

    // dont recurse for value type, Nullable<T> and strings 
    if (propType.IsValueType || propType == typeof(string)) 
    { 
     var sourceVal = sourcePi.GetValue(source, null); 
     if(sourceVal != null) 
      pi.SetValue(target, sourceVal, null); 
    } 
    else // recursively map inner class properties 
    { 
     var props = propType.GetProperties(BindingFlags.Public | 
                BindingFlags.NonPublic | 
                BindingFlags.Instance); 

     foreach (var p in props) 
     { 
      var sourcePropValue = sourcePi.GetValue(source, null); 
      var targetPropValue = pi.GetValue(target, null); 

      if (sourcePropValue != null) 
      { 
       if (targetPropValue == null) // replace 
       { 
        pi.SetValue(target, sourcePi.GetValue(source, null), null); 
       } 
       else 
       { 
        MergeProperty(p, sourcePropValue, targetPropValue); 
       } 
      } 
     } 

    } 
} 

आप तरीकों इस तरह से उपयोग कर सकते हैं:

public static void Map(ExpandoObject source, T destination) 
{ 
    if (source == null) 
     throw new ArgumentNullException("source"); 
    if (destination == null) 
     throw new ArgumentNullException("destination"); 

    foreach (var kv in source) 
    { 
     PropertyInfo p; 
     if (PropertyMap.TryGetValue(kv.Key.ToLower(), out p)) 
     { 
      MergeProperty(p, source, destination); 
     } 
     else 
     { 
      // do similar merge for fields 
     } 
    } 
} 
+0

खैर अच्छा विस्तृत जवाब है, हालांकि, यह InnerClass के साथ काम करेंगे, लेकिन यह यह बदल देगा यह नक्शा नहीं। .. क्योंकि मैं मानों को अद्यतन (मानचित्र) करना चाहता हूं क्योंकि यह शेष गैर-आंतरिक गुणों के साथ किया गया है [दूसरे शब्दों में (स्रोत से शून्य मानों को अनदेखा करें और मौजूदा लोगों को शून्य से प्रतिस्थापित न करें)]।इसके अलावा 3,2,1 के बजाय उत्तर 1,2,3 की व्यवस्था करने पर विचार करें: डी –

+0

क्या आप विस्तारित कर सकते हैं 'यह इसे मानचित्र नहीं करेगा'? क्या आप क्लोन करना चाहते हैं? 'गैर आंतरिक मूल्य' कैसे मैप किए जाते हैं और प्रतिस्थापित नहीं होते हैं? मुझे समझ नहीं आया। – YK1

+0

mmm, मैं क्या कहना चाहता हूं। उस मैपर का काम गंतव्य ऑब्जेक्ट फ़ील्ड्स/गुणों को अद्यतन करना है, और अद्यतन के साथ मेरा क्या मतलब है यदि मैपर को स्रोत में शून्य क्षेत्र/संपत्ति मिली है, तो यह गंतव्य से संबंधित क्षेत्र/संपत्ति को शून्य के साथ प्रतिस्थापित नहीं करेगा बल्कि केवल रखें यह, अन्यथा यह इसे अद्यतन करेगा। दूसरा जो मुझे यहां कमी है वह यह है कि मैं चाहता हूं कि मैपर को यह देखने के लिए कि क्षेत्र/संपत्ति में अधिक आंतरिक गुण हैं, तो यह वही प्रक्रिया करता है (यह मेरा मतलब है रिकर्सिव मैपिंग के साथ) –

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