2011-01-09 13 views
11

तरीकों भी के लिए एक ही:मैं दो संपत्ति इन्फोस या विधियों की तुलना कैसे कर सकता हूं?

मैं PropertyInfo या तरीकों में से दो स्थितियों वर्ग में उपयोग होने वाली से निकाला गया है GetProperty() या GetMember() के माध्यम से दिया जाता रहा आदि, (या एक MemberExpression शायद से)।

मैं निर्धारित करने के लिए अगर वे तथ्य यह है एक ही संपत्ति या एक ही विधि का जिक्र कर रहे हैं तो

(propertyOne == propertyTwo) 

या

(methodOne == methodTwo) 

जाहिर है कि नहीं जा रहा है चाहता हूँ वास्तव में काम करते हैं, आप हो सकता है के लिए एक ही संपत्ति को देख रहे हैं, लेकिन इसे कक्षा पदानुक्रम के विभिन्न स्तरों से निकाला जा सकता है (जिसमें आमतौर पर propertyOne != propertyTwo)

cours के ई, मैं DeclaringType को देखो सकता है, और फिर से अनुरोध संपत्ति, लेकिन यह एक बिट भ्रमित हो रही शुरू होता है जब तुम सोच के बारे में

  • गुण/तरीके इंटरफेस पर घोषित कर दिया और वर्गों पर लागू
  • गुण/तरीके घोषित शुरू एक आधार वर्ग (लगभग) और व्युत्पन्न वर्ग पर ओवरराइड पर
  • गुण/तरीके, एक आधार वर्ग पर घोषित 'नए' के ​​साथ अधिरोहित

(आईएल दुनिया में इस कुछ भी नहीं विशेष iirc है) के अंत में दिन, मैं बस एक बुद्धिमान ईक करने में सक्षम होना चाहता हूँ दो गुणों या दो तरीकों के बीच uality जांच, मैं 80% सुनिश्चित हूं कि उपर्युक्त बुलेट बिंदु सभी किनारे के मामलों को कवर नहीं करते हैं, और जब मैं बस बैठ सकता हूं, परीक्षणों का एक समूह लिख सकता हूं और खेलना शुरू कर सकता हूं, मैं अच्छी तरह से जानता हूं कि इन अवधारणाओं को वास्तव में कार्यान्वित करने के बारे में मेरा निम्न स्तर का ज्ञान उत्कृष्ट नहीं है, और मुझे उम्मीद है कि यह पहले से ही उत्तर दिया गया विषय है और मैं बस खोज में चूसता हूं।

सर्वश्रेष्ठ उत्तर मुझे तरीकों कि इसके बाद के संस्करण प्राप्त की एक जोड़ी देना होगा समझा क्या बढ़त मामलों का ध्यान रखा गया है और यही कारण है कि :-)


स्पष्टीकरण:

वस्तुतः मुझे यकीन है कि वे एक ही संपत्ति कर रहे हैं, यहाँ कुछ उदाहरण हैं बनाना चाहते

public interface IFoo 
{ 
    string Bar { get; set; } 
} 

public class Foo : IFoo 
{ 
    string Bar { get; set; } 
} 

typeof(IFoo).GetProperty("Bar") 

और

typeof(Foo).GetProperty("Bar") 

दो संपत्ति infos, जो बराबर नहीं हैं वापसी करेंगे:

public class BaseClass 
{ 
    public string SomeProperty { get; set ; } 
} 

public class DerivedClass : BaseClass { } 


typeof(BaseClass).GetMethod("SomeProperty") 

और

typeof(DerivedClass).GetProperty("SomeProperty") 

मैं वास्तव में याद नहीं कर सकते हैं कि ये दोनों वापसी बराबर अब वस्तुओं, लेकिन मेरी दुनिया में वे बराबर हैं।

इसी तरह:

public class BaseClass 
{ 
    public virtual SomeMethod() { } 
} 

public class DerivedClass 
{ 
    public override SomeMethod() { } 
} 

typeof(BaseClass).GetMethod("SomeMethod") 

और

typeof(DerivedClass).GetProperty("SomeMethod") 

फिर, ये मैच नहीं होगा - लेकिन मैं उन्हें चाहते हैं (मैं जानता हूँ कि वे विशेष रूप से बराबर नहीं कर रहे हैं, लेकिन मेरे डोमेन वे कर रहे हैं क्योंकि वे एक ही मूल संपत्ति का संदर्भ देते हैं)

मैं इसे संरचनात्मक रूप से कर सकता हूं, लेकिन यह 'गलत' होगा।

इसके अलावा नोट्स:

कैसे तुम भी संपत्ति है कि एक और संपत्ति छुपा के अनुरोध करते हैं? लगता है कि मेरे पहले के अनुमानों में से एक अमान्य था, कि GetProperty("name") का डिफ़ॉल्ट कार्यान्वयन वर्तमान स्तर को डिफ़ॉल्ट रूप से संदर्भित करेगा।

BindingFlags.DeclaringType बस वापस लौटने के लिए प्रकट होता है!

+1

"बेस क्लास पर घोषित गुण/तरीके, 'नया' के साथ ओवरराइड किया गया -" इसे वास्तव में * छुपा * कहा जाता है, और वे * निश्चित रूप से * अलग-अलग सदस्य हैं। उन्हें बिल्कुल "बराबर" के रूप में देखने का अर्थ नहीं है। – Ani

+0

ठीक है, मैंने बस बुरी तरह से वाक्यांश दिया - उस परिस्थिति में सच होने के लिए तुलना कोड लिखना बहुत कठिन होगा ;-) - यह अभी भी एक दुखी पथ है जिसे परीक्षण की आवश्यकता है, क्योंकि मैं संरचनात्मक तुलना कोड के बारे में सोच सकता हूं जो सच हो जाएगा । –

+1

क्या आप इस प्रश्न को बेहतर तरीके से स्पष्ट कर सकते हैं? क्या आप 'string.GetHashCode == int.GetHashCode' चाहते हैं (क्योंकि उनकी मूल परिभाषाएं एक ही प्रकार पर हैं - 'ऑब्जेक्ट')। 'सूची के बारे में कैसे करें।' बनाम 'हैशसेट काउंटर' (दोनों लागू' आईसीओलेक्शन काउंटर')? – Ani

उत्तर

3

अपने IFoo/Foo उदाहरण से PropertyInfo वस्तुओं पर एक नज़र ले रहा है, हम इन निष्कर्ष तक पहुँचने कर सकते हैं:

  1. क्या वर्ग/इंटरफेस संपत्ति शुरू में घोषित किया गया था देखने के लिए कोई सीधा रास्ता नहीं है।
  2. इसलिए, यह जांचने के लिए कि वास्तव में संपत्ति को पूर्वजों के वर्ग पर घोषित किया गया था, हमें पूर्वजों पर पुन: प्रयास करने की आवश्यकता है और देखें कि संपत्ति उनके ऊपर भी मौजूद है या नहीं।
  3. समान इंटरफ़ेस के लिए जाता है, हमें Type.GetInterfaces पर कॉल करने और वहां से काम करने की आवश्यकता है। यह मत भूलना कि इंटरफेस अन्य इंटरफेस को कार्यान्वित कर सकता है, इसलिए इसे रिकर्सिव होना चाहिए।

तो चलो इसके पास एक दरार है। सबसे पहले, विरासत में मिला गुण कवर करने के लिए: इन को एक साथ मिलाकर

PropertyInfo GetImplementedProperty(PropertyInfo pi) 
{ 
    var type = pi.DeclaringType; 
    var interfaces = type.GetInterfaces(); 

    if (interfaces.Length == 0) { 
     return pi; 
    } 

    var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public; 
    var query = from iface in interfaces 
       let implementedProperty = iface.GetProperty(pi.Name, flags) 
       where implementedProperty != pi 
       select implementedProperty; 

    return query.DefaultIfEmpty(pi).First(); 
} 

:

PropertyInfo GetRootProperty(PropertyInfo pi) 
{ 
    var type = pi.DeclaringType; 

    while (true) { 
     type = type.BaseType; 

     if (type == null) { 
      return pi; 
     } 

     var flags = BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance | 
        BindingFlags.Public | BindingFlags.Static; 
     var inheritedProperty = type.GetProperty(pi.Name, flags); 

     if (inheritedProperty == null) { 
      return pi; 
     } 

     pi = inheritedProperty; 
    } 
} 

अब, गुण इंटरफेस में घोषित कवर करने के लिए (डीएफएस के साथ खोज)

PropertyInfo GetSourceProperty(PropertyInfo pi) 
{ 
    var inherited = this.GetRootProperty(pi); 
    if (inherited != pi) { 
     return inherited; 
    } 

    var implemented = this.GetImplementedProperty(pi); 
    if (implemented != pi) { 
     return implemented; 
    } 

    return pi; 
} 

यह काम करना चाहिए। यह एक ही नाम के साथ अनुक्रमित गुणों को ध्यान में नहीं रखता है लेकिन विभिन्न प्रकारों और/या अनुक्रमण पैरामीटर की संख्या, ताकि पाठक के लिए प्रोवर्बियल व्यायाम के रूप में छोड़ा जा सके।

अस्वीकरण: मैंने इसे संकलित नहीं किया (अभी परीक्षण चलाने के लिए कोई समय नहीं)। यह "उत्तर" के लिए शुरुआती बिंदु के रूप में है, क्योंकि अभी तक कोई भी नहीं है।

+0

अभी भी एक उत्कृष्ट शुरुआत - मेरे पास परीक्षण का एक सूट और मेरा ढेर है अभी तक असंगत लेकिन समान) कोड का परीक्षण करने के लिए - मैं आपकी पोस्ट पढ़ूंगा और देख सकता हूं कि मतभेद कहां झूठ बोलते हैं और आप पर वापस आते हैं :-) –

+0

बह, अब तक इतना अच्छा है लेकिन मोनो और एमएस.नेट के बीच एक अंतर है इसलिए मैं पूरी तरह से सत्यापित नहीं कर सकता (किसी कारण से मेरे विंडोज़ वीएम पर परीक्षण चलाने में सक्षम नहीं है) - एक बार मैंने एज केस –

+0

सत्यापित करने के बाद इसे काम कर लिया और अपना जवाब स्वीकार कर लिया, ठीक है, तो लगभग - FYI यह पर्याप्त नहीं है एक GetP करने के लिए roperty, हमें इंटरफ़ेसमैप का उपयोग करके संपत्ति से मेल खाना पड़ेगा - इसके अलावा कोशेर अब तक –

1

ऐसा लगता है कि आप तुलना करना चाहते हैं कि दो MemberInfo के घोषित प्रकारों की जांच करना आसान होगा। आधार/उप-वर्ग संबंध के मामले में, यदि घोषित प्रकार समान हैं तो उन्हें एक ही घोषणा का प्रतिनिधित्व करना चाहिए।इंटरफेस के मामले में, वे एक ही होना चाहिए, अगर घोषित इंटरफ़ेस प्रकार के अन्य इंटरफेस की सूची में है:

Type type1 = methodInfo1.DeclaringType; 
Type type2 = methodInfo2.DeclaringType; 

bool same = type1 == type2 || 
    type1.IsInterface && type2.GetInterfaces.Contains(type1) || 
    type2.IsInterface && type1.GetInterfaces.Contains(type2); 

एक बात के इंटरफेस के लिए 'इंटरफ़ेस मानचित्रण' है बारे में पता होना करने के लिए - Type.GetInterfaceMap जिसका अर्थ है किसी इंटरफ़ेस में घोषित विधियों में लागू करने वाले वर्ग में समान नाम नहीं हो सकता है, जो आपके वर्तमान दृष्टिकोण का कारण नहीं लग रहा है।

+0

के साथ एक राउंड-अप करूंगा यदि सदस्य में से एक ओवरराइड हो रहा है तो यह अभी भी झूठ वापस आ जाएगा एक बेस सदस्य (मेरी परिभाषा में वे वही हैं), और निश्चित रूप से वापस आ जाएंगे यदि दोनों प्रकार पूरी तरह अलग हैं लेकिन समान प्रकार हैं - स्वीकार्य रूप से यह केवल एक टाइपो है क्योंकि आपने इसे अभी जवाब में डाला है: -) - हालांकि लिया गया बिंदु, यह वास्तव में बहुत आसान है –

+1

मुझे लगता है कि लंबा समाधान सबसे अच्छा है - दोनों सदस्यों की जड़ पाएं, और उन लोगों की तुलना करें, सदस्य की तुलना करने पर भरोसा करते हैं/सदस्य दो सीधे सीधे –

2

मुझे बिल्कुल यकीन नहीं है कि आपको इसकी क्या आवश्यकता है, लेकिन मुझे लगता है कि इस मामले में समानता की आपकी परिभाषा है "क्या दो विधि इंफोस उसी विधि का आह्वान करते हैं यदि" तो फिर तुम सच में भी तुलना में एक प्रकार निर्दिष्ट करने की जरूरत है, उदाहरण के लिए इस पर विचार करें:

public interface IFoo 
{ 
    void AMethod(); 
} 

public interface IBar 
{ 
    void AMethod(); 
} 

public class FooBar : IFoo, IBar 
{ 
    void AMethod(); 
} 

जाहिर typeof (IFoo) .GetMethod ("AMethod") और typeof (Ibar) .GetMethod ("AMethod") बराबर नहीं हैं, वे भी संबंधित नहीं हैं, लेकिन वे FooBar के उदाहरण पर एक ही विधि का आह्वान करते हैं। तो क्या आपको पसंद आ सकते एक तुलना विधि है कि तीन तर्क लेता है:

bool WillInvokeSameMethodOnType(MethodInfo method1, MethodInfo method2, Type type) 

बाहर FakeItEasy में वर्ग MethodInfoManager चेक, यह हो सकता है कि आप क्या चाहते: http://code.google.com/p/fakeiteasy/source/browse/Source/FakeItEasy/Core/MethodInfoManager.cs?r=8888fefbc508fb02d5435a3e33774500bec498b3

+0

मेकिंग पर त्रुटि प्रवण होता है उपलब्ध प्रकार काफी मुश्किल होगा, लेकिन DeclaringType आदि निश्चित रूप से पर्याप्त होगा? मुझे लगता है कि MethodInfoManager करीब आता है - लेकिन आप नए बनाम आभासी कैसे प्रबंधित करते हैं? –

+0

यह सुनिश्चित नहीं है कि आप वास्तव में क्या पूछ रहे हैं, मेरे मामले में विशेष रूप से नए बनाम आभासी की कोई ज़रूरत नहीं है क्योंकि मुझे दिलचस्पी है कि विधि में इन्फोस उसी विधि को प्रेषित करेगा। –

2

तो, यह एक कठिन कुकी था और इससे पहले कि मैं उबाऊ विवरण में जाता हूं, मैं यह कहूंगा, मैं केवल संरचनात्मक तुलना करने का विकल्प चुनता हूं, क्योंकि केवल नीचे गिर जाएगा, जब कोई सदस्य छिपाता है सी # में 'नया' कीवर्ड वाला दूसरा सदस्य - यह निर्णय लिया कि इस समस्या में अन्य समस्याओं की तुलना में इस प्रणाली में एक छोटा सा मुद्दा था कि इस समस्या के लिए उचित समाधान ई अगर यह गलत हो जाता है (और यह गलत हो जाता है, तो मेरा विश्वास करें)।

मैं ऊपर एक जवाब को स्वीकार कर लिया है, क्योंकि यह समस्या को हल करने के करीब आ गया - केवल एक समस्या यह है कि यह प्रकृति में अभी भी संरचनात्मक है (और मैं प्रकार से है कि प्राप्त कर सकते हैं/नाम/तर्क की जांच)

हालांकि कुछ मतभेद हैं, मुख्य रूप से गेटप्रोपर्टी को कॉल करने के बजाय इंटरफ़ेस मानचित्र को देखना आवश्यक है - यह एक महत्वपूर्ण विवरण है - यहां मेरी संशोधित विधि है जो कुछ परिस्थितियों में खत्म हो जाएगी।

private PropertyInfo GetImplementedProperty(PropertyInfo pi) 
    { 
     var type = pi.DeclaringType; 
     var interfaces = type.GetInterfaces(); 

     for(int interfaceIndex = 0; interfaceIndex < interfaces.Length; interfaceIndex++) 
     { 
      var iface = interfaces[interfaceIndex]; 
      var interfaceMethods = type.GetInterfaceMap(iface).TargetMethods; 

      MethodInfo matchingMethod = null; 
      for (int x = 0; x < interfaceMethods.Length; x++) 
      { 
       if (pi.GetGetMethod().LooseCompare(interfaceMethods[x]) || pi.GetSetMethod().LooseCompare(interfaceMethods[x])) 
       { 
        matchingMethod = type.GetInterfaceMap(iface).InterfaceMethods[x]; 
        break; 
       } 
      } 
      if (matchingMethod == null) continue; 

      var interfacePi = from i in interfaces 
           from property in i.GetProperties() 
           where property.GetGetMethod().LooseCompare(matchingMethod) || property.GetSetMethod().LooseCompare(matchingMethod) 
           select property; 

      return interfacePi.First(); 
     } 

     return pi; 
    } 

मैं देखना हो एक सदस्य किसी अन्य सदस्य छिपा था पर देने समाप्त हो गया, और निम्न हैक के लिए चला गया: मैं एक धारणा है कि यहाँ का उपयोग कर एक संपत्ति/विधि 'नया बनाने

private PropertyInfo GetRootProperty(PropertyInfo pi) 
    { 
     if ((pi.GetGetMethod().Attributes & MethodAttributes.Virtual) != MethodAttributes.Virtual) { return pi; } 

     var type = pi.DeclaringType; 

     while (true) 
     { 
      type = type.BaseType; 

      if (type == null) 
      { 
       return pi; 
      } 

      var flags = BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance | 
         BindingFlags.Public | BindingFlags.Static; 

      var inheritedProperty = type.GetProperty(pi.Name, flags); 

      if (inheritedProperty == null) 
      { 
       return pi; 
      } 

      pi = inheritedProperty; 
     } 
    } 

'कीवर्ड वर्चुअल कीवर्ड का भी उपयोग नहीं करेगा, क्योंकि' नया 'एक किनारे का मामला है, वैसे भी, यह काफी संभावना नहीं है।

यह तय करने से पहले मुझे यह मिला कि यह मेरे परीक्षण पास कर चुका है और मैं उससे खुश था। (और इससे पहले कि मैंने केवल संरचनात्मक जांच का चयन करने का फैसला किया ...) मुझे आशा है कि यह किसी भी व्यक्ति के लिए उपयोग में है जो भविष्य में इस तरह से ठोकर खाती है।

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

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