Я использовал несколько решений не совсем этой проблемы, но схожие вещи.
1 - Вы можете получить собственный прокси из RealProxy и воспользоваться предоставленным перехватом вызововинфраструктурой удаленного взаимодействия .NET.Преимущество состоит в том, что это очень просто, но ограничение заключается в том, что вам нужно прокси-интерфейс либо интерфейса и использовать отражение для вызова членов вашего внутреннего класса, либо проксируемый класс должен наследоваться от MarshalByRrefObject.
Пока я не решаюсь дать пример кода, просто потому, что он не будет полным, и я, вероятно, получу пламя.Но вот десятиминутный кусок кода, чтобы вы указали на правильные классы и т. Д. Осторожно, я работаю только с IMethodCallMessage, так что это не завершено, но должно работать как демонстрация.
class LoggingProxy<T> : RealProxy where T : MarshalByRefObject, new()
{
T _innerObject;
public static T Create()
{
LoggingProxy<T> realProxy = new LoggingProxy<T>();
T transparentProxy = (T)realProxy.GetTransparentProxy();
return transparentProxy;
}
private LoggingProxy() : base(typeof(T))
{
_innerObject = new T();
}
public override IMessage Invoke(IMessage msg)
{
if (msg is IMethodCallMessage)
{
IMethodCallMessage methodCall = msg as IMethodCallMessage;
System.Diagnostics.Debug.WriteLine("Enter: " + methodCall.MethodName);
IMessage returnMessage = RemotingServices.ExecuteMessage(_innerObject, msg as IMethodCallMessage);
System.Diagnostics.Debug.WriteLine("Exit: " + methodCall.MethodName);
return returnMessage;
}
return null;
}
}
Это можетиспользовать следующим образом:
class MyClass : MarshalByRefObject
{
public int Age
{
get;
set;
}
}
MyClass o = LoggingProxy<MyClass>.Create();
o.Age = 10;
Выше будет регистрировать вызов set_Age для проксируемого экземпляра MyClass.
2 - Еще одна альтернатива, но гораздо больше работы - создать прокси-класс, которыйдинамически генерирует тип, производный от передаваемого вами типа, и предоставляет реализации всех методов и свойств базового типа.Сгенерированные методы и т. Д. Будут выполнять регистрацию, вызывать реализацию базового класса и т. Д., Аналогично примеру RealProxy.Используя VS var type, вы, вероятно, можете избежать необходимости наследования от типа и скорее использовать агрегирование для этого прокси-сервера, так что вы все равно будете иметь поддержку intelli-sense и не будете делать все методы / свойства виртуальными.К сожалению, нет примера, это слишком много на данный момент.Но вы можете посмотреть на использование CodeDom или, что еще лучше, Reflection.Emit для построения динамического типа.Динамический код может сделать что-то подобное предложенному в ответе @ tvanfosson.
3- И, наконец, вы можете использовать DynamicObject для выполнения большей части вышеперечисленного, недостатком является то, что у вас не будет компиляциипроверка времени вызовов методов и отсутствие смысла.Опять же, здесь приведен минимальный пример.
public class DynamicProxy : System.Dynamic.DynamicObject
{
private object _innerObject;
private Type _innerType;
public DynamicProxy(object inner)
{
if (inner == null) throw new ArgumentNullException("inner");
_innerObject = inner;
_innerType = _innerObject.GetType();
}
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result)
{
System.Diagnostics.Debug.WriteLine("Enter: ", binder.Name);
try
{
result = _innerType.InvokeMember(
binder.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod,
null, _innerObject, args);
}
catch (MissingMemberException)
{
return base.TryInvokeMember(binder, args, out result);
}
finally
{
System.Diagnostics.Debug.WriteLine("Exit: ", binder.Name);
}
return true;
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
{
System.Diagnostics.Debug.WriteLine("Enter: ", binder.Name);
try
{
result = _innerType.InvokeMember(
binder.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty,
null, _innerObject, null);
}
catch (MissingMemberException)
{
return base.TryGetMember(binder, out result);
}
finally
{
System.Diagnostics.Debug.WriteLine("Exit: ", binder.Name);
}
return true;
}
public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value)
{
System.Diagnostics.Debug.WriteLine("Enter: ", binder.Name);
try
{
_innerType.InvokeMember(
binder.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
null, _innerObject, new object[]{ value });
}
catch (MissingMemberException)
{
return base.TrySetMember(binder, value);
}
finally
{
System.Diagnostics.Debug.WriteLine("Exit: ", binder.Name);
}
return true;
}
public override string ToString()
{
try
{
System.Diagnostics.Debug.WriteLine("Enter: ToString");
return _innerObject.ToString();
}
finally
{
System.Diagnostics.Debug.WriteLine("Exit: ToString");
}
}
}
, который используется примерно так:
dynamic o2 = new DynamicProxy(new MyClass());
o.Age = 10;
Есть несколько вариантов развертывания собственного решения, в качестве альтернативы вы можете посмотреть на некоторыеиз предварительно поддержанных решений.Возможно, это лучший путь, но это должно дать вам некоторое представление о том, как некоторые из решений, возможно, были реализованы.