Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
298 views
in Technique[技术] by (71.8m points)

c# - Is there a way to "override" a method with reflection?

Without inherit but only with reflection is it possible to dynamically change the code of a method in C#?

something like :

nameSpaceA.Foo.method1 = aDelegate;

I cannot change/edit The Foo Class.

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

My final objective is to change dynamicaly the code of :

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

In System.Xml.Xsl.Runtime.XslConvert.cs

to turn :

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

into :

if (!item.IsNode)
    throw new XslTransformException(Res.XPath_NodeSetExpected, item.value); 
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The first part of this answer is wrong, I'm only leaving it so that the evolution in the comments makes sense. Please see the EDIT(s).

You're not looking for reflection, but emission (which is the other way around).

In particular, there's a method that does just what you want, lucky you!

See TypeBuilder.DefineMethodOverride

EDIT:
Writing this answer, I just remembered that re-mix allows you to do this too. It's way harder though.

Re-mix is a framework that "simulates" mixins in C#. In its basic aspect, you can think of it as interfaces with default implementations. If you go further, it becomes much more than that.

EDIT 2: Here is an example of use for re-mix (implementing INotifyPropertyChanged on a class that doesn't support it, and has no idea of mixins).

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;
    }
}

And the test:

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

Please note that:

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

and

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

and

[ImplementsINPC] //commented out in my example

Have the exact same effect. It is a matter of where you wish to define that a particular mixin is applied to a particular class.

Example 2: overriding Equals and 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<>))
        {

        }
    }

That example is my implementation of the hands-on lab given with re-mix. You can find more information there.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...