2009-02-03 8 views
7

Когда у вас есть автомобиль класса, который реализует IVehicle, и вы хотите обернуть его в декоратор, который переадресует все вызовы на автомобиль и подсчитывает их, как бы вы это сделали?Каков самый короткий способ реализации класса прокси или декоратора в C#?

В Ruby я мог просто построить декоратор без каких-либо методов и использовать метод_missing для переадресации всех вызовов на объект автомобиля.

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

Есть ли что-нибудь подобное в C#?


обновление:

на основе ответившим и что i've читать о System.Reflection.Emit должно быть возможно написать метод похож на это:

Type proxyBuilder(Type someType, delagate functionToBeApplied, Object forward) 

где тип реализует весь интерфейс someType, выполняет функцию FunctionToBeApplied, а затем перенаправляет вызов метода объекту, возвращая его возврат.

Есть ли какая-нибудь библиотека, которая делает именно это, или мне нужно написать свой собственный?

ответ

4

Для проксирования вы можете посмотреть «RealProxy», если вы хотите использовать стандартные типы, это немного хлопот, который нужно использовать (и для этого требуются, чтобы ваши классы наследовали от MarshalByRefObject).

public class TestProxy<T> : RealProxy where T : class 
{ 
    public T Instance { get { return (T)GetTransparentProxy(); } } 
    private readonly MarshalByRefObject refObject; 
    private readonly string uri; 

    public TestProxy() : base(typeof(T)) 
    { 
     refObject = (MarshalByRefObject)Activator.CreateInstance(typeof(T)); 
     var objRef = RemotingServices.Marshal(refObject); 
     uri = objRef.URI; 
    } 

    // You can find more info on what can be done in here off MSDN. 
    public override IMessage Invoke(IMessage message) 
    { 
     Console.WriteLine("Invoke!"); 
     message.Properties["__Uri"] = uri; 
     return ChannelServices.SyncDispatchMessage(message); 
    } 
} 

В качестве альтернативы вы можете получить «DynamicProxy» от замка .. Он работает немного лучше в моем опыте ..

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

Решение Marc будет иметь лучшую производительность.

2

К сожалению, в C# нет поддержки mixin. Таким образом, вам нужно будет реализовать все методы или использовать некоторые тяжелые функции reflection.emit для этого. Другой альтернативой является (по желанию) прокси/декоратора базовый класс ...

abstract class FooBase : IFoo { 
    protected FooBase(IFoo next) {this.next = next;} 
    private readonly IFoo next; 
    public virtual void Bar() { // one of the interface methods 
     next.Bar(); 
    } 
    public virtual int Blop() { // one of the interface methods 
     return next.Blop(); 
    } 
    // etc 
} 

затем

class SomeFoo : FooBase { 
    public SomeFoo(IFoo next) : base(next) {} 
    public override void Bar() {...} 
} 

отмечая, что использование FooBase является строго обязательным; любой IFoo разрешен.

+0

, пожалуйста, объясните в двух словах, что означает «использование« FooBase »строго необязательно» означает? это предикат «разрешено любое« IFoo' »? точка с запятой заставляет меня читать инструкцию (ы) отдельно, и аргумент является самодостаточным, чтобы добавить путаницу. несмотря на cpt. Очевидный шепот: «это просто означает, что« FooBase »может быть заменен любым другим« IFoo », реализующим« IFoo »способом« FooBase' », я буду разочарован, если все будет так просто. не разочарован ответом, который хорош, а скорее с моей паранойей. извините за «вербальность» (теперь мне нужно найти идиому, соответствующую этому явлению) –

+1

Я думаю, что это ваш неутешительный ответ; код должен зависеть только от 'IFoo'; 'FooBase' - это просто удобство для кода, который выбирает реализацию' IFoo'. –

+0

спасибо!если у вас есть время, ответьте еще на два вопроса: ** 1) ** этой теме уже 6 лет, похоже, с тех пор ничего не изменилось, и способы решения проблемы все те же? * (никогда не думал, что я пропущу C++, но у него есть '->' перегрузка) * ** 2) ** я ошибаюсь: вы говорите, что это плохая практика наследовать от абстрактных классов? Я сам считаю их интерфейсами с реализацией по умолчанию, и они довольно удобны. и, по-видимому, может ссылаться на экземпляры SomeFoo как 'IFoo'. * (в то же время, ms внедренный метод расширений методов)) * –