Решение множественного наследования (для предварительно приготовленных классов)

Что мне нужно: класс с двумя родителями, которые 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,

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

Чтобы это работало, вам нужно программное обеспечение, которое понимает эти атрибуты и обрабатывает вашу сборку, добавляя необходимый код к аннотированным методам / классам.

Для C# существует PostSharp. Смотрите здесь для введения.

Другие вопросы по тегам