Как сделать простой динамический прокси в С#
Я хочу создать динамический прокси-объект, чтобы добавить определенные функции к объекту.
в основном я хочу получить объект, обернуть его объектом, который выглядит идентично оригиналу, который я получил, и перехватить все вызовы.
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", мне нужно было иметь прокси-классы, а не интерфейсы.
Есть два решения:
Кстати, второй подход имеет значительные ограничения, вы не можете проксировать не виртуальные методы.
Ответ 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, как я показал, а затем отказаться от утиного катания.
Я сделал прозрачную расширяемую версию этого объектного прокси и открыл его здесь.
Ответ 3
В дополнение к Castle.DynamicProxy, есть также LinFu.DynamicProxy на Github.
Ответ 4
Взгляните на PostSharp.
Я не знаю, как сделать то, что вы хотите в vanilla.Net, но PostSharp предлагает такие вещи, как "OnMethodBoundaryAspect", который может использоваться для замены или переноса кода внутри метода.
Я использовал его для выполнения таких действий, как ведение журнала, проверка параметров, обработка исключений и т.д.
Существует бесплатное издание Community Edition, которое должно работать на вас. Вам понадобится его установить на вашей машине разработки, а также любой сервер сборки, который вы используете.
Ответ 5
Вот простой пример Создание динамического прокси с использованием С# Emit
Вы также можете использовать структуру AOP, например PostSharp
Ответ 6
Другим вариантом является ContextBoundObject
.
В CodeProject появилась статья о 8-9 лет назад, используя этот подход для отслеживания вызовов методов.