Как сделать простой динамический прокси в С#

Я хочу создать динамический прокси-объект, чтобы добавить определенные функции к объекту.

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

class Wrapper : DynamicProxy// dynamic proxy is not a reall class, but i guess something like this exists...
{
    public static T Wrap(T obj)
    {
        return (T) new Wrapper(obj);
    }

    public override object InterceptCall(MethodInfo info, object[] args)
    {
        // do stuff
    }

}

Чтобы уточнить, я хочу сделать что-то похожее на канал WCF factory...


Я добавляю щедрость, потому что мне нужен хороший способ для прокси-классов (а не интерфейсов) и для обработки не виртуальных методов (как если бы я унаследовал и добавил metond под ключевым словом "новое" ). Я уверен, что все это очень возможно, так как .Net делает это.

Ответ 1

Я должен был написать это раньше, но неважно.

У моей проблемы была специальная "gotcha", мне нужно было иметь прокси-классы, а не интерфейсы.

Есть два решения:

  • Real Proxy и друзья, в основном означает использование .Net Remoting. Требуется один для наследования из ContextBoundObject.

  • Построение прокси-сервера с помощью System.Reflection.Emit, как сделано spring вы также можете посмотреть код их ProxyFactoryObject. Вот еще три статьи на тема.

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

Ответ 2

Вы можете сделать это с помощью комбинации DynamicObject и ImpromptuInterface, но вам нужно будет иметь интерфейс, который реализует функции и свойства, которые вы хотите прокси.

public interface IDoStuff
{
    void Foo();
}

public class Wrapper<T> : DynamicObject
{
    private readonly T _wrappedObject;

    public static T1 Wrap<T1>(T obj) where T1 : class
    {
        if (!typeof(T1).IsInterface)
            throw new ArgumentException("T1 must be an Interface");

        return new Wrapper<T>(obj).ActLike<T1>();
    }

    //you can make the contructor private so you are forced to use the Wrap method.
    private Wrapper(T obj)
    {
        _wrappedObject = obj;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        try
        {
            //do stuff here

            //call _wrappedObject object
            result = _wrappedObject.GetType().GetMethod(binder.Name).Invoke(_wrappedObject, args);
            return true;
        }
        catch
        {
            result = null;
            return false;
        }
    }
}

Вы можете отказаться от выбора типа безопасности и пойти с DynamicObject, как я показал, а затем отказаться от утиного катания.

Я сделал прозрачную расширяемую версию этого объектного прокси и открыл его здесь.

Ответ 4

Взгляните на PostSharp. Я не знаю, как сделать то, что вы хотите в vanilla.Net, но PostSharp предлагает такие вещи, как "OnMethodBoundaryAspect", который может использоваться для замены или переноса кода внутри метода.

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

Существует бесплатное издание Community Edition, которое должно работать на вас. Вам понадобится его установить на вашей машине разработки, а также любой сервер сборки, который вы используете.

Ответ 6

Другим вариантом является ContextBoundObject.

В CodeProject появилась статья о 8-9 лет назад, используя этот подход для отслеживания вызовов методов.