简体   繁体   中英

Cloning a method in c#

Suppose I have a class A:

class A
{
    void b() {...}
}

and a class B:

class B
{
    A m;
}

This way, if I write B x , I can call xmb() .

What I need is to dynamically create a method b() inside the B class, so I could use it as xb() (of course, the results from calls xmb() and xb() should be the same).

How can I do it?

You could do this with delegates, in modern C# this could look like this

public class A
{
    public void b() {...}
}

public class B
{
    private A m = new A();
    public Action b = ()=>m.b();
}

public void Main()
{
     new B().b(); // This now invokes your delegates that invokes the b method on it's internal m object
}

Could also just do it with classical methods and simply expose ab method that does the exact same thing, don't see anything special / hard here? If you're trying to accomplish something else you need to clarify your question, like if you want to automate this there are easy compile time (T4 text templates) or at runtime (generating dynamic proxies).

There is one generic solution (where you won't have to fe create delegates for every method from A you want). Unfortunately, It won't be a strongly-typed one. If you want so, please see other answers.

class A
{
    public int B()
    {
        return 1;
    }
}

class B : DynamicObject
{
    private readonly A m = new A();

    private static readonly Lazy<IEnumerable<MethodInfo>> AMethods =
        new Lazy<IEnumerable<MethodInfo>>(() =>
                                          {
                                              var type = typeof (A);
                                              return type.GetMethods(
                                                  BindingFlags.Instance | 
                                                  BindingFlags.Public);
                                          });

    public override bool TryInvokeMember(
                           InvokeMemberBinder binder, 
                           object[] args, 
                           out object result)
    {
        if (base.TryInvokeMember(binder, args, out result))
        {
            return true;
        }

        var methods = AMethods.Value;

        var method = methods.SingleOrDefault(mth => mth.Name == binder.Name); 
            // TODO: additional match (arguments type to handle overloads)
        if (method == null)
        {
            result = null;
            return false;
        }

        result = method.Invoke(this.m, args);

        return true;
    }

    public int OtherBMethods()
    {
        return 2;
    }
}

Usage:

var b = new B();  
int result = ((dynamic)b).B();    
int other = b.OtherBMethods(); 

or

dynamic b = new B();
int result = b.B();
int other = b.OtherBMethods();

What you are going to do is implement Decorator pattern in C#.

GoF defines Decorator pattern as "Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

I would like to recommend look throught this article "Understanding and Implementing Decorator Pattern in C#" .

I have created a simple example of the Decorator pattern implementation when you decorate Concrete with A and B functionality.

interface IDecorator
{
    void Print();
}

class Concrete : IDecorator
{
    public void Print()
    {
        Console.WriteLine("-> Concrete");
    }
}

class A : IDecorator
{
    IDecorator decorator;
    public A(IDecorator decorator)
    {
        this.decorator = decorator;
    }
    public void Print()
    {
        decorator.Print();
        Console.WriteLine("-> A");
    }
}

class B : IDecorator
{
    IDecorator decorator;
    public B(IDecorator decorator)
    {
        this.decorator = decorator;
    }
    public void Print()
    {
        decorator.Print();
        Console.WriteLine("-> B");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("concrete object that should be decorated");
        var concrete = new Concrete();
        concrete.Print();

        Console.WriteLine("let's decorate this object with A decorator");
        var decoratedWithA = new A(concrete);
        decoratedWithA.Print();

        Console.WriteLine("let's decorate this object with B decorator");
        var decoratedWithB = new B(concrete);
        decoratedWithB.Print();

        Console.WriteLine("let's decorate concrete with A and B");
        var decoratedWithAB = new B(new A(concrete));
        decoratedWithAB.Print();
    }
}

I have an abstract A class and classes A1 : A, A2 : A, A3 : A. Then i also have a method named c(). I want to create classes A1_with_c_method, A2_with_c_method, A3_with_c_methos while leaving A1, A2 and A3 unharmed. What is the best way to do this? – h8red

You could do something like this:

abstract class A
{
}

class A1 : A
{
}

class A2 : A
{
}

class A3 : A
{
}

#region Not a good idea, because too many classes

class A1_with_c : A1
{
    public void c() { }
}

class A2_with_c : A2
{
    public void c() { }
}

class A3_with_c : A3
{
    public void c() { }
}

#endregion


// Decorate A with the c() method
class BaseDecorator
{
    public A Instance { get; private set; }
    public BaseDecorator(A instance)
    {
        Instance = instance;
    }

    public virtual void c()
    {
        // do something with instance
    }
}

class Decorator : BaseDecorator
{
    BaseDecorator decorator;
    public Decorator(BaseDecorator decorator)
        : base(decorator.Instance)
    {
        this.decorator = decorator;
    }
    public override void c()
    {
        Console.WriteLine("Ok");
    }
}

class Program
{
    static void Main(string[] args)
    {
        // not good
        new A1_with_c().c();
        new A2_with_c().c();
        new A3_with_c().c();

        // better
        var a_with_c = new BaseDecorator(new A1());
        a_with_c.c();

        // Let's decorate with something interesting
        new Decorator(a_with_c).c();
    }
}

I agree with the comments that this really seems odd and I'm wondering why you would ever want to do this but here is a possibility for you.

interface IHasMethodb
{
    void b();
}

class A : IHasMethodb
{
    public void b() { ... }
}

class B : IHasMethodb
{
    A m;
    public void b() { return m.b(); }
}

Is this what you're trying to do?

It seems like you either want the concept of wrapping a method, which in your example is as simple as:

class A {
   public void b() { ... }
}

class B {
   A m;
   public void b() { m.b(); }
}

Allowing you to:

B x = new B();
x.b();

If you want to be able to "dynamically create" the method then this might be more applicable, using an Action<T> to allow you to do whatever you like with the A instance, without actually exposing it:

class A {
   public void b() {...}
}

class B {
   A m;
   public Action<A> doSomethingWithA;

   public void b() {
      if (doSomethingWithA != null)
         doSomethingWithA(m);
   }
}

Then you can:

B x = new B();
x.doSomethingWithA = a => a.b();
x.b();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM