2010-06-17 19 views
11

35 फ़ील्ड और 2 ऑब्जेक्ट्स वाली कक्षा को विभिन्न फ़ील्ड मानों की एक निश्चित संख्या के साथ देखते हुए। क्या सूची < स्ट्रिंग> फ़ील्ड नाम के साथ एक वस्तु है जहां वस्तु निम्नानुसार है?2 ऑब्जेक्ट्स की तुलना करना और विभिन्न मानों के साथ फ़ील्ड की एक सूची पुनर्प्राप्त करें

उदा

obj1.Name = "aaa"; 
obj1.LastName = "bbb"; 
obj1.Address = "xcs"; 
obj2.Name = "aaa"; 
obj2.LastName = "ccc"; 
obj2.Address = "jk"; 

उद्देश्य:

list<<String>String> containing 2 Strings LastName and Address 

मैं रास्ते जाने के लिए के रूप में प्रतिबिंब देखते हैं लेकिन 35 क्षेत्रों के साथ मुझे डर है कि यह बहुत भारी है हूँ। कोई अन्य विचार, जैसे linq?

+1

प्रतिबिंब की लागत: यह आराम के लिए मूल्य-प्रकार बनाम रेफरी प्रकार की वस्तुओं, इनबिल्ट आईएल समानता, समानता ऑपरेटरों (==), और EqualityComparer<T> हैंडलिंग, काम करने के लिए मक्खी (कैश्ड) पर आईएल बनाता है सापेक्ष है आप यह कितनी बार कर रहे हैं? ** ** बहुत तेज़ी से ऐसा करने के तरीके हैं, लेकिन यदि आप इसे एक तंग पाश में नहीं कर रहे हैं, तो प्रतिबिंब ठीक होना चाहिए (और सरल है)। –

+0

(उदाहरण के लिए, इसे ILGenerator या अभिव्यक्ति के माध्यम से लिखना संभव होगा - लेकिन क्या जटिलता जरूरी है? मुझे बताएं ...) –

+0

मार्क, मैं इसे डब्ल्यूसीएफ के अंदर कर रहा हूं लेकिन इसका उपयोग कुछ उपयोगकर्ताओं के लिए किया जाएगा, तो मैंने प्रतिबिंब के लिए फैसला किया। आपके प्रयासों के लिए धन्यवाद। – ajj

उत्तर

1

प्रतिबिंब इस के साथ जाने का तरीका है और मुझे नहीं लगता कि 35 फ़ील्ड एक समस्या है।

(खुद को पूरी तरह भ्रमित करने के बाद मैं सोचने के लिए वापस आ गया कि मैं प्रश्न समझता हूं और प्रतिबिंब इसके लिए ठीक होगा)।

34

ठीक है; यह बहुत ही अधिक सामान्य प्रयासों की तुलना में अधिक प्रयास करता है, लेकिन यह एक उपयोगी उपयोगिता विधि हो सकती है।

using System.Collections.Generic; 
using System.Reflection; 
using System.Reflection.Emit; 

namespace ConsoleApplication2 
{ 
    using System; 
    class Program 
    { 
     static void Main() 
     { 
      WriteDeltas(new Foo {X = 123, Y = DateTime.Today, Z = null}, 
         new Foo {X = 124, Y = DateTime.Today, Z = null}); 
      WriteDeltas(new Foo { X = 123, Y = DateTime.Today, Z = null }, 
         new Foo { X = 123, Y = DateTime.Now, Z = new Dummy()}); 
      WriteDeltas(new Bar { X = 123, Y = DateTime.Today, Z = null }, 
         new Bar { X = 124, Y = DateTime.Today, Z = null }); 
      WriteDeltas(new Bar { X = 123, Y = DateTime.Today, Z = null }, 
         new Bar { X = 123, Y = DateTime.Now, Z = new Dummy() }); 
     } 
     static void WriteDeltas<T>(T x, T y) 
     { 
      Console.WriteLine("----"); 
      foreach(string delta in PropertyComparer<T>.GetDeltas(x,y)) 
      { 
       Console.WriteLine(delta); 
      } 

     } 

    } 
    class Dummy {} 
    class Foo 
    { 
     public int X { get; set; } 
     public DateTime Y { get; set; } 
     public Dummy Z { get; set; } 
    } 
    struct Bar 
    { 
     public int X { get; set; } 
     public DateTime Y { get; set; } 
     public Dummy Z { get; set; } 
    } 

    public static class PropertyComparer<T> 
    { 
     private static readonly Func<T, T, List<string>> getDeltas; 
     static PropertyComparer() 
     { 
      var dyn = new DynamicMethod(":getDeltas", typeof (List<string>), new[] {typeof (T), typeof (T)},typeof(T)); 
      var il = dyn.GetILGenerator(); 
      il.Emit(OpCodes.Newobj, typeof (List<string>).GetConstructor(Type.EmptyTypes)); 
      bool isValueType = typeof (T).IsValueType; 
      OpCode callType = isValueType ? OpCodes.Call : OpCodes.Callvirt; 
      var add = typeof(List<string>).GetMethod("Add"); 
      foreach (var prop in typeof(T).GetProperties()) 
      { 
       if (!prop.CanRead) continue; 
       Label next = il.DefineLabel(); 
       switch (Type.GetTypeCode(prop.PropertyType)) 
       { 
        case TypeCode.Boolean: 
        case TypeCode.Byte: 
        case TypeCode.Char: 
        case TypeCode.Double: 
        case TypeCode.Int16: 
        case TypeCode.Int32: 
        case TypeCode.Int64: 
        case TypeCode.SByte: 
        case TypeCode.Single: 
        case TypeCode.UInt16: 
        case TypeCode.UInt32: 
        case TypeCode.UInt64: 
         if(isValueType) {il.Emit(OpCodes.Ldarga_S, (byte)0);} else {il.Emit(OpCodes.Ldarg_0);} 
         il.EmitCall(callType, prop.GetGetMethod(), null); 
         if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)1); } else { il.Emit(OpCodes.Ldarg_1); } 
         il.EmitCall(callType, prop.GetGetMethod(), null); 
         il.Emit(OpCodes.Ceq); 
         break; 
        default: 
         var pp = new Type[] {prop.PropertyType, prop.PropertyType}; 
         var eq = prop.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static, null, pp, null); 
         if (eq != null) 
         { 
          if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)0); } else { il.Emit(OpCodes.Ldarg_0); } 
          il.EmitCall(callType, prop.GetGetMethod(), null); 
          if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)1); } else { il.Emit(OpCodes.Ldarg_1); } 
          il.EmitCall(callType, prop.GetGetMethod(), null); 
          il.EmitCall(OpCodes.Call, eq, null); 

         } 
         else 
         { 
          il.EmitCall(OpCodes.Call, typeof(EqualityComparer<>).MakeGenericType(prop.PropertyType).GetProperty("Default").GetGetMethod(), null); 
          if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)0); } else { il.Emit(OpCodes.Ldarg_0); } 
          il.EmitCall(callType, prop.GetGetMethod(), null); 
          if (isValueType) { il.Emit(OpCodes.Ldarga_S, (byte)1); } else { il.Emit(OpCodes.Ldarg_1); } 
          il.EmitCall(callType, prop.GetGetMethod(), null); 
          il.EmitCall(OpCodes.Callvirt, typeof(EqualityComparer<>).MakeGenericType(prop.PropertyType).GetMethod("Equals", pp), null); 
         } 
         break; 
       } 
       il.Emit(OpCodes.Brtrue_S, next); // equal 
       il.Emit(OpCodes.Dup); 
       il.Emit(OpCodes.Ldstr, prop.Name); 
       il.EmitCall(OpCodes.Callvirt, add, null); 
       il.MarkLabel(next); 
      } 
      il.Emit(OpCodes.Ret); 
      getDeltas = (Func<T, T, List<string>>)dyn.CreateDelegate(typeof (Func<T, T, List<string>>)); 
     } 
     public static List<string> GetDeltas(T x, T y) { return getDeltas(x, y); } 

    } 
} 
+1

यह कमाल है। क्या इस उपयोगिता को रिकर्सिव बनाना मुश्किल होगा (यानी ऑब्जेक्ट ग्राफ़ चलना)? :-) –

+0

@ ट्रॉय - एकल वस्तुओं के लिए, बुरा नहीं। सूचियां एक दर्द हैं। –

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