2012-03-13 15 views
18

विरासत के बिना, लेकिन केवल प्रतिबिंब के साथ सी # में किसी विधि के कोड को गतिशील रूप से बदलना संभव है?क्या प्रतिबिंब के साथ एक विधि "ओवरराइड" करने का कोई तरीका है?

कुछ की तरह:

nameSpaceA.Foo.method1 = aDelegate; 

मैं नहीं बदल सकते/फू क्लास संपादित करें।

public static IList<XPathNavigator> EnsureNodeSet(IList<XPathItem> listItems); 

System.Xml.Xsl.Runtime.XslConvert.cs में

चालू करने के लिए:

if (!item.IsNode) 
    throw new XslTransformException(Res.XPath_NodeSetExpected, string.Empty); 

namespace nameSpaceA 
{ 
    class Foo 
    { 
     private void method1() 
     { 
      // ... some Code 
     } 
    } 
} 

मेरे अंतिम उद्देश्य dynamicaly के कोड बदलने के लिए है

में:

if (!item.IsNode) 
    throw new XslTransformException(Res.XPath_NodeSetExpected, item.value); 
+4

नहीं है, सी # बंदर समझौता नहीं किया जा सकता, कि अगर सवाल यह है कि ... –

+1

@MarcGravell उत्सर्जन कि सक्षम बनाता है। इसके अलावा, पुनः मिश्रण भी कर सकते हैं। सी # पूरी तरह से बंदर-पैच हो सकता है! –

+1

@ बाबून ने आपके उत्तर –

उत्तर

12

इस उत्तर का पहला भाग गलत है, मैं केवल इसे छोड़ रहा हूं ताकि टिप्पणियों में विकास समझ में आता है। कृपया EDIT देखें।

आप प्रतिबिंब की तलाश नहीं कर रहे हैं, लेकिन उत्सर्जन (जो कि दूसरी तरफ है)।

विशेष रूप से, एक विधि है जो आप चाहते हैं, भाग्यशाली आप!

देखें TypeBuilder.DefineMethodOverride

संपादित करें:
इस उत्तर लेखन, मैं सिर्फ याद आया कि re-mix आप ऐसा भी कर सकते हैं। यद्यपि यह कठिन है हालांकि।

पुन: मिश्रण एक ढांचा है जो सी # में मिश्रित "अनुकरण" करता है। अपने मूल पहलू में, आप इसके बारे में डिफ़ॉल्ट कार्यान्वयन के साथ इंटरफेस के रूप में सोच सकते हैं। यदि आप आगे जाते हैं, तो यह उससे कहीं अधिक हो जाता है।

संपादित करें 2: यहां पुन: मिश्रण के लिए उपयोग का एक उदाहरण है (एक वर्ग पर INotifyProperty को लागू करना जो इसका समर्थन नहीं करता है, और मिश्रणों का कोई विचार नहीं है)।

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Remotion.Mixins; 
using System.ComponentModel; 
using MixinTest; 

[assembly: Mix(typeof(INPCTester), typeof(INotifyPropertyChangedMixin))] 

namespace MixinTest 
{ 
    //[Remotion.Mixins.CompleteInterface(typeof(INPCTester))] 
    public interface ICustomINPC : INotifyPropertyChanged 
    { 
     void RaisePropertyChanged(string prop); 
    } 

    //[Extends(typeof(INPCTester))] 
    public class INotifyPropertyChangedMixin : Mixin<object>, ICustomINPC 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     public void RaisePropertyChanged(string prop) 
     { 
      PropertyChangedEventHandler handler = this.PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(prop)); 
      } 
     } 
    } 

    public class ImplementsINPCAttribute : UsesAttribute 
    { 
     public ImplementsINPCAttribute() 
      : base(typeof(INotifyPropertyChangedMixin)) 
     { 

     } 
    } 

    //[ImplementsINPC] 
    public class INPCTester 
    { 
     private string m_Name; 
     public string Name 
     { 
      get { return m_Name; } 
      set 
      { 
       if (m_Name != value) 
       { 
        m_Name = value; 
        ((ICustomINPC)this).RaisePropertyChanged("Name"); 
       } 
      } 
     } 
    } 

    public class INPCTestWithoutMixin : ICustomINPC 
    { 
     private string m_Name; 
     public string Name 
     { 
      get { return m_Name; } 
      set 
      { 
       if (m_Name != value) 
       { 
        m_Name = value; 
        this.RaisePropertyChanged("Name"); 
       } 
      } 
     } 

     public void RaisePropertyChanged(string prop) 
     { 
      PropertyChangedEventHandler handler = this.PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(prop)); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 
} 

और परीक्षण:

static void INPCImplementation() 
     { 
      Console.WriteLine("INPC implementation and usage"); 

      var inpc = ObjectFactory.Create<INPCTester>(ParamList.Empty); 

      Console.WriteLine("The resulting object is castable as INPC: " + (inpc is INotifyPropertyChanged)); 

      ((INotifyPropertyChanged)inpc).PropertyChanged += inpc_PropertyChanged; 

      inpc.Name = "New name!"; 
      ((INotifyPropertyChanged)inpc).PropertyChanged -= inpc_PropertyChanged; 
      Console.WriteLine(); 
     } 

static void inpc_PropertyChanged(object sender, PropertyChangedEventArgs e) 
     { 
      Console.WriteLine("Hello, world! Property's name: " + e.PropertyName); 
     } 
//OUTPUT: 
//INPC implementation and usage 
//The resulting object is castable as INPC: True 
//Hello, world! Property's name: Name 

कृपया ध्यान दें कि:

[assembly: Mix(typeof(INPCTester), typeof(INotifyPropertyChangedMixin))] 

और

[Extends(typeof(INPCTester))] //commented out in my example 

और

सटीक वही प्रभाव डालें। यह एक बात है कि आप कहां परिभाषित करना चाहते हैं कि किसी विशेष वर्ग पर एक विशेष मिश्रण लागू होता है।

उदाहरण 2: अधिभावी बराबर और GetHashCode

public class EquatableByValuesMixin<[BindToTargetType]T> : Mixin<T>, IEquatable<T> where T : class 
    { 
     private static readonly FieldInfo[] m_TargetFields = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

     bool IEquatable<T>.Equals(T other) 
     { 
      if (other == null) 
       return false; 
      if (Target.GetType() != other.GetType()) 
       return false; 
      for (int i = 0; i < m_TargetFields.Length; i++) 
      { 
       object thisFieldValue = m_TargetFields[i].GetValue(Target); 
       object otherFieldValue = m_TargetFields[i].GetValue(other); 

       if (!Equals(thisFieldValue, otherFieldValue)) 
        return false; 
      } 
      return true; 
     } 

     [OverrideTarget] 
     public new bool Equals(object other) 
     { 
      return ((IEquatable<T>)this).Equals(other as T); 
     } 

     [OverrideTarget] 
     public new int GetHashCode() 
     { 
      int i = 0; 
      foreach (FieldInfo f in m_TargetFields) 
       i ^= f.GetValue(Target).GetHashCode(); 
      return i; 
     } 
    } 

    public class EquatableByValuesAttribute : UsesAttribute 
    { 
     public EquatableByValuesAttribute() 
      : base(typeof(EquatableByValuesMixin<>)) 
     { 

     } 
    } 

उदाहरण हाथ प्रयोगशाला फिर से मिश्रण के साथ दिया की मेरी कार्यान्वयन है यही कारण है कि। आप वहां अधिक जानकारी पा सकते हैं।

+0

पर उत्तर दिया है आप किसी आंतरिक वर्ग पर एक निजी, गैर-वर्चुअल विधि बदलने के लिए DefineMethodOverride का उपयोग नहीं कर सकते हैं। यदि आप कर सकते हैं, तो मुझे यह देखना अच्छा लगेगा। समान रूप से, आपको उप-प्रकार बनाने के लिए निर्माण को भी बदलने की आवश्यकता होगी, जो मानता है कि आपके पास * * * Foo' (जो आवश्यक नहीं है) पर नियंत्रण है –

+0

@MarcGravell मैंने व्यक्तिगत रूप से इसे आजमाया नहीं है, लेकिन मैं सोचने के इच्छुक हूं कि निजी तरीकों को ओवरराइड करने का कोई मतलब नहीं है। हालांकि, उदाहरण के परिदृश्य को उन्होंने अपने संपादन के बाद दिया, ऐसा लगता है कि उनके पास उस विधि तक पहुंच है जिसे वह ओवरराइड करना चाहता है। तो, यह निजी नहीं है। किसी भी तरह से, फिर से मिश्रण निश्चित रूप से देखने के लायक है! –

+0

"मैं देख सकता हूं कि विधि परावर्तक में क्या करती है" और "यह एक सार्वजनिक आभासी विधि है जिसके लिए मुझे पहुंच है" - मुझे सच में नहीं लगता कि उत्सर्जन यहां मदद करने जा रहा है (और मैं कहता हूं कि किसी के रूप में जो नियमित रूप से उत्सर्जित करता है) –

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

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