Решение множественного наследования (для предварительно приготовленных классов)
Что мне нужно: класс с двумя родителями, которые ContextBoundObject
и другой класс.
Почему: мне нужно получить доступ к ContextBoundOject
регистрировать вызовы метода.
Композиция работает? На данный момент нет (типы не распознаются, между прочим).
Есть ли другие способы сделать это? Да, но не настолько автоматизируемый и без сторонних компонентов (возможно, Т4 мог бы сделать, но я не эксперт).
Более подробное объяснение.
Мне нужно расширить системные классы (некоторые из которых уже MarshalByRefObject
(который является родителем ContextBoundObject
) для родителя, например ServiceBase
а также FileSystemWatcher
а некоторые нет, например Exception
а также Timer
) для доступа к некоторым внутренним работам фреймворка, чтобы я мог регистрировать вызовы методов (пока; в будущем это может измениться).
Если я использую этот способ, мне нужно только добавить имя класса к объекту, который я хочу зарегистрировать, вместо того, чтобы добавлять вызовы регистрации для каждого метода, но, очевидно, я не могу сделать это:
public class MyService:ServiceBase,ContextBoundObject,IDisposable{
public MyService(){}
public Dispose(){}
}
так что можно попробовать обычное решение, интерфейсы, но потом, если я вызову Run as in:
ServiceBase.Run(new MyService());
используя гипотетический интерфейс IServiceBase, он не будет работать, потому что тип ServiceBase не преобразуется в IServiceBase - он не наследуется ни от какого интерфейса. Проблема еще хуже с исключениями: throw
принимает только тип по убыванию Exception
,
И наоборот, создание интерфейса IContextBoundObject, похоже, тоже не работает: механизм ведения журнала не работает с помощью методов, поэтому мне не нужно реализовывать какие-либо, только атрибут и несколько небольших внутренних классов (и наследование от ContextBoundObject
даже не из MarshalByRefObject
, метаданные которого представлены практически одинаково).
Из того, что я вижу, начиная от ContextBoundObject
помещает расширенный класс в Proxy
(вероятно, потому что таким образом вызовы метода используют SyncProcessMessage(IMessage) и, следовательно, могут быть перехвачены и зарегистрированы), возможно, есть способ сделать это без наследования, или, возможно, могут быть методы предварительной или посткомпиляции, доступные для окружающих методов с вызовами регистрации (как текстовые шаблоны T4), я не знаю.
Если кто-то хочет взглянуть на это, я использовал настроенную версию MSTestExtentions в моей программе для ведения журналов (вызовов методов). Любые идеи приветствуются. Может потребоваться больше объяснений, просто спросите.
2 ответа
Экспериментируя с прокси, я нашел способ, который, по-видимому, регистрирует явные вызовы.
По сути я создаю RealProxy
как в примере в MSDN, затем получить TransparentProxy
и использовать это как обычный объект.
Регистрация ведется в Invoke
метод переопределен в настроенном RealProxy
учебный класс.
static void Main(){
...
var ServiceClassProxy=new ServiceRealProxy(typeof(AServiceBaseClass),new object[]{/*args*/});
aServiceInstance=(AServiceBaseClass)ServiceClassProxy.GetTransparentProxy();
ServiceBase.Run(aServiceInstance);
...
}
В прокси-классе Invoke
будет сделано так:
class ServiceRealProxy:RealProxy{
...
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
public override IMessage Invoke(IMessage myIMessage){
// remember to set the "__Uri" property you get in the constructor
...
/* logging before */
myReturnMessage = ChannelServices.SyncDispatchMessage(myIMessage);
/* logging after */
...
return myReturnMessage;
// it could be useful making a switch for all the derived types from IMessage; I see 18 of them, from
// System.Runtime.Remoting.Messaging.ConstructionCall
// ... to
// System.Runtime.Remoting.Messaging.TransitionCall
}
...
}
Мне еще предстоит провести тщательное расследование, но регистрация произошла. Это не ответ на мою первоначальную проблему, потому что я все еще должен проверить это на классах, которые не наследуются от MarshalByRefObject
,
Вызов методов ведения журнала обычно выполняется с использованием атрибутов для аннотирования классов или методов, для которых вы хотите включить ведение журнала. Это называется аспектно-ориентированным программированием.
Чтобы это работало, вам нужно программное обеспечение, которое понимает эти атрибуты и обрабатывает вашу сборку, добавляя необходимый код к аннотированным методам / классам.