Как я могу сделать делегат относиться к конкретной версии методы? - PullRequest
4 голосов
/ 13 ноября 2010

Я хотел бы создать делегат, который вызывает конкретный метод экземпляра, к сожалению, кажется, что если метод является виртуальным, будет вызываться переопределение метода для наследующего класса, а не базовой версии.

    public class Base{
        public virtual void Method(){
            Console.WriteLine("Base");
        }
    }

    public class Child : Base{
        public override void Method(){
            Console.WriteLine("Child");
        }
    }

Если где-то еще в коде у меня есть следующее:

var action = Delegate.CreateDelegate(typeof(Action<Base>), typeof(Base).GetMethod("Method")) as Action<Base>;
action(new Child());

Вывод этой программы Child.Мне бы очень хотелось, чтобы это было Base.Я пробовал то же самое с деревьями выражений, и я получаю тот же результат, поскольку в выдаваемом IL используется метод callvirt.Является ли единственный способ сделать что-то подобное действительно с Reflection.Emit?

Причина, по которой я спрашиваю, заключается в том, что я использую конструктор типов для переопределения поведения класса.Если бы я сам написал метод, я мог бы просто пойти base.Method() или что-то в этом роде, но некоторые методы поведения метода могут быть определены только динамически во время выполнения, поскольку учет многих возможных случаев был бы очень утомительным.

Поскольку я создаю класс, производный от Base во время выполнения, если я пытаюсь вызвать Method() внутри перегрузки Method(), я делаю это приводит к бесконечной рекурсии и исключениям переполнения стека.(не очень хорошо).

Это для проекта в стиле AOP, где я добавляю некоторую логику в методы во время выполнения.Я помечаю методы атрибутами, затем у меня есть конструктор типов, который создает methodBuilders, снабжающий тело построителя методов деревом выражений, используя CompileToMethod(methodbuilder) http://msdn.microsoft.com/en-us/library/dd728224.aspx, Это на тонну проще, чем рефлексия.нетривиально, что я добавляю.Цель состоит в том, чтобы у меня на фабрике появился новый класс, который всякий раз, когда я вызываю Method(), сначала выполняет некоторую логику, прежде чем в конечном итоге вызвать базовую реализацию.

Ответы [ 4 ]

1 голос
/ 13 ноября 2010

Может быть, вы можете использовать такой обходной путь:

public class Base{
    public virtual void Method(){
        MethodImpl();
    }
    public void MethodImpl(){
        Console.WriteLine("Base");
    }
}

public class Child : Base{
    public override void Method(){
        Console.WriteLine("Child");
    }
}

Теперь вы можете создать делегата, представляющего MethodImpl.

1 голос
/ 13 ноября 2010

Да, Reflection.Emit - единственный способ, предоставляемый платформой .NET для реализации перегрузок методов. Поскольку другие API-интерфейсы не используются при перегрузке методов, они не обеспечивают какой-либо путь к базовой реализации.

0 голосов
/ 14 ноября 2010

Поскольку Reflection.Emit такой сложный способ создания целого метода, я бы рекомендовал использовать Reflection.Emit для создания частных методов только для вызова методов base.Тогда вы можете обратиться к этим методам из ваших Expression s.

0 голосов
/ 13 ноября 2010

Что здесь должно произойти?

class Base { public abstract void Method(); }
class Child {
    public override void Method() {
        Console.WriteLine("Child.Method");
    }
}

Action<Base> magicalAction = // defined somehow
magicalAction(new Child()); // aiya!

Вы пытаетесь победить суть виртуальных методов.Почему?

...