2008-11-13 12 views
18

तो अगर मेरे पास है:प्रतिबिंब मुझे कैसे बताता है जब कोई संपत्ति 'नए' कीवर्ड वाले विरासत वाले सदस्य को छुपा रही है?

public class ChildClass : BaseClass 
{ 
    public new virtual string TempProperty { get; set; } 
} 

public class BaseClass 
{ 
    public virtual string TempProperty { get; set; } 
} 

मैं प्रतिबिंब का उपयोग कैसे को देखने के लिए कि ChildClass TempProperty के आधार कार्यान्वयन छिपा है सकते हैं?

मुझे पसंद है अगर आप वीबी उपयोग कर रहे हैं संपत्ति आप देख रहे हैं "IsHideBySig" है जवाब, सी # और vb.net

उत्तर

21

हमें संपत्ति के बजाय यहां संपत्ति के तरीकों के संदर्भ में निपटना होगा, क्योंकि यह संपत्ति के प्राप्त/सेट विधियों को वास्तव में संपत्ति के बजाय ओवरराइड किया जाता है। मैं प्राप्त विधि का उपयोग करूंगा क्योंकि आपके पास कभी भी संपत्ति नहीं होनी चाहिए, हालांकि एक पूर्ण समाधान की कमी की जांच करनी चाहिए।

कई मामलों में उत्सर्जित आईएल को देखते हुए, बेस प्रॉपर्टी की 'गेट' विधि में मेटाडाटा टोकन होगा (यह सी # कंपाइलर से है; अन्य hidebysig को उनके विधि छिपाने वाले अर्थशास्त्र के आधार पर उत्सर्जित नहीं कर सकते हैं,

non-virtual : .method public hidebysig specialname instance 
virtual  : .method public hidebysig specialname newslot virtual instance 

व्युत्पन्न एक निम्न टोकन होगा: जो मामले में विधि छिपाने-दर-नाम) होगा

override : .method public hidebysig specialname virtual instance 
new   : .method public hidebysig specialname instance 
new virtual : .method public hidebysig specialname newslot virtual instance 

तो हम इस से देख सकते हैं कि यह संभव नहीं है विधि के मेटाडेटा टोकन से पूरी तरह से बताएं कि क्या यह है new है क्योंकि गैर वर्चुअल बेस विधि में गैर-वर्चुअल new विधि के समान टोकन हैं, और वर्चुअल बेस विधि में new virtual विधि के समान टोकन हैं।

क्या हम कह सकते हैं कि यह एक आधार विधि को ओवरराइड करता है, तो विधि virtual टोकन नहीं लेकिन newslot टोकन है तो छाया यह है, यानी बजाय है

var prop = typeof(ChildClass).GetProperty("TempProperty"); 
var getMethod = prop.GetGetMethod(); 
if ((getMethod.Attributes & MethodAttributes.Virtual) != 0 && 
    (getMethod.Attributes & MethodAttributes.NewSlot) == 0) 
{ 
    // the property's 'get' method is an override 
} 

मान लिया जाये, तो, हम पाते हैं कि विधि 'के लिए' एक ओवरराइड, हम जानना चाहते आधार वर्ग है कि यह पीछा कर रहा है में एक संपत्ति है या नहीं चाहते नहीं है। समस्या यह है कि क्योंकि विधि एक अलग विधि तालिका स्लॉट में है, लेकिन वास्तव में यह छायांकन के तरीके से कोई सीधा संबंध नहीं है। तो हम वास्तव में क्या कह रहे हैं "क्या बेस प्रकार में कोई तरीका है जो छायांकन के मानदंडों को पूरा करता है", जो इस बात पर निर्भर करता है कि विधि hidebysig या छुपाएं-नाम है या नहीं।

पूर्व के लिए हमें यह जांचने की आवश्यकता है कि बेस क्लास में कोई तरीका है जो हस्ताक्षर से बिल्कुल मेल खाता है, जबकि बाद के लिए हमें यह जांचने की आवश्यकता है कि उसके पास एक ही नाम के साथ कोई विधि है, इसलिए ऊपर से कोड जारी रखें:

else 
{ 
    if (getMethod.IsHideBySig) 
    { 
     var flags = getMethod.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic; 
     flags |= getMethod.IsStatic ? BindingFlags.Static : BindingFlags.Instance; 
     var paramTypes = getMethod.GetParameters().Select(p => p.ParameterType).ToArray(); 
     if (getMethod.DeclaringType.BaseType.GetMethod(getMethod.Name, flags, null, paramTypes, null) != null) 
     { 
      // the property's 'get' method shadows by signature 
     } 
    } 
    else 
    { 
     var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance; 
     if (getMethod.DeclaringType.BaseType.GetMethods(flags).Any(m => m.Name == getMethod.Name)) 
     { 
      // the property's 'get' method shadows by name 
     } 
    } 
} 

मुझे लगता है कि यह सबसे अधिक तरीका है, लेकिन मुझे अभी भी नहीं लगता कि यह बिल्कुल सही है। शुरुआत के लिए मैं नाम से छिपाने से पूरी तरह से परिचित नहीं हूं क्योंकि सी # इसका समर्थन नहीं करता है और यह मेरे द्वारा उपयोग किए जाने वाले बहुत अधिक है, इसलिए मैं यहां कोड में गलत हो सकता हूं जो इंगित करता है कि एक आवृत्ति विधि स्थिर हो सकती है। मुझे केस संवेदनशीलता समस्या के बारे में भी पता नहीं है (उदाहरण के लिए वीबी में Foo नामक एक विधि को foo नामक एक विधि कहा जा सकता है, यदि दोनों के पास एक ही हस्ताक्षर था और hidebysig दोनों थे - सी # में उत्तर नहीं है, लेकिन अगर उत्तर हाँ है वीबी तो इसका मतलब है कि इस सवाल का जवाब वास्तव में nondeterministic है)।

खैर, मुझे यकीन नहीं है कि यह सब कुछ कितना मददगार है, यह स्पष्ट करने के अलावा कि यह वास्तव में एक कठिन समस्या है, जैसा कि मैंने सोचा था कि यह होगा (या मैंने वास्तव में कुछ याद किया है जो मैं चाहता हूं जानना चाहता हूँ!)। लेकिन उम्मीद है कि इसमें पर्याप्त सामग्री है जो यह आपको प्राप्त करने में मदद करने में आपकी सहायता करती है।

+0

सभी महान जानकारी के लिए धन्यवाद। मैं जल्द ही इसका प्रयोग करूँगा। –

+0

मुझे यकीन है कि आपको बेसटाइप.GetMethod() पर अपने कॉल में 'बाइंडिंगफ्लैग.एक्सएक्ट बाइंडिंग' भी शामिल करने की आवश्यकता है। अन्यथा, यह रिपोर्ट करेगा कि 'बूल इक्वाल्स (फू अन्य)' छुपाएं 'ऑब्जेक्ट। एक्वाल्स (ऑब्जेक्ट) ' – RobSiklos

+0

इस उत्तर में समस्या यह है कि लाइन var [prop = typeof (ChildClass) .GetProperty (" TempProperty "); ] यदि आपका प्रकार कार्यान्वयनकर्ता है तो फेंक देगा और त्रुटि होगी। आपको एक "संदिग्ध मैच मिलेगा।" और यदि आप एक .GetProperties() करते हैं तो आप देखेंगे कि छायांकित संपत्ति दो बार दिखाई देगी। इसलिए इस काम को करने का एकमात्र तरीका इंडेक्स द्वारा गुणों के माध्यम से संभव चक्र है और उन्हें परीक्षण करें और फिर डुप्लिकेट नामों का ट्रैक रखें और तय करें कि किस का उपयोग करना है। – jrandomuser

-1

सुधार के बीच नास्तिक होने के लिए चाहते हैं। यह इस मामले में गलत होगा कि "नया" कीवर्ड किसी विधि/संपत्ति को परिभाषित करने के लिए उपयोग किया गया था।

सी # मामले में, दोनों उदाहरणों को "hidebysig" के रूप में आउटपुट किया जाता है। ग्रेग को इंगित करने के लिए धन्यवाद। मुझे एहसास नहीं हुआ कि मैंने केवल वीबी में इसका परीक्षण किया था। यहां नमूना वीबी कोड है जो इस व्यवहार को दोहराएगा।

Module Module1 

    Class Foo 
     Public Function SomeFunc() As Integer 
      Return 42 
     End Function 
    End Class 

    Class Bar 
     Inherits Foo 
     Public Shadows Function SomeFunc() As Integer 
      Return 36 
     End Function 
    End Class 

    Sub Main() 
     Dim type = GetType(Bar) 
     Dim func = type.GetMethod("SomeFunc") 
     Stop 
    End Sub 

End Module 
+0

क्या आपने यह कोशिश की है? यह सही नहीं है। यह हमेशा सी # में सच होता है, भले ही यह आभासी, नया, ओवरराइड, आदि –

+0

@ ग्रेग - क्या आप एक और जवाब जानते हैं? क्या आप थे जिनके पास दूसरी पोस्ट थी लेकिन इसे हटा दिया गया? मैंने दस्तावेज़ों और आपके अधिकार को पढ़ा है - यह भाषा अज्ञेयवादी नहीं है और सी # के लिए भी "सत्य" नहीं "झूठी" वापस करनी चाहिए। –

0

मैंने कभी भी ऐसा नहीं किया जो आप करने की कोशिश कर रहे हैं लेकिन MethodInfo.GetBaseDefinition() विधि आप जो खोज रहे हैं वह प्रतीत होता है।

यह विधिInfo देता है यह विधि ओवरराइडिंग है।

MSDN से:

किसी दिए गए विधि (प्रकार सदस्यों में वर्णित के रूप newslot के रूप में) नया कीवर्ड निर्दिष्ट है, तो दी विधि दिया जाता है।

+0

नोट: यह इस सटीक उदाहरण के लिए काम करेगा। यदि वर्चुअल कीवर्ड उत्सर्जित होता है तो यह उदाहरण के लिए काम नहीं करेगा। – JaredPar

3

प्रतिबिंब ऐसा प्रतीत नहीं होता डिफ़ॉल्ट रूप से आप को यह दे देंगे ताकि आप अपने रोल करना होगा:

public static bool IsHidingMember(this PropertyInfo self) 
{ 
    Type baseType = self.DeclaringType.BaseType; 
    PropertyInfo baseProperty = baseType.GetProperty(self.Name, self.PropertyType); 

    if (baseProperty == null) 
    { 
     return false; 
    } 

    if (baseProperty.DeclaringType == self.DeclaringType) 
    { 
     return false; 
    } 

    var baseMethodDefinition = baseProperty.GetGetMethod().GetBaseDefinition(); 
    var thisMethodDefinition = self.GetGetMethod().GetBaseDefinition(); 

    return baseMethodDefinition.DeclaringType != thisMethodDefinition.DeclaringType; 
} 

सुनिश्चित नहीं हैं कि इस अनुक्रमित गुणों के साथ हालांकि काम करेंगे,!

+0

यह आशाजनक लग रहा है। इस दृष्टिकोण के साथ आप क्या सीमाएं देखते हैं? –