2009-12-18 2 views
2

У меня есть ситуация, когда я хотел бы перехватить вызовы в свойствах .NET. Я смотрю на DynamicProxy в Castle и, похоже, работает нормально. Но, кажется, для того, чтобы использовать его, я должен начать с новым объектом, то есть я не могу сделать что-то вроде этого:Обтекание существующих объектов, чтобы перехватить метод/вызовы свойств в .NET

MyType myType = new MyType(); 
myType.Property = "Test"; 

... 

MyType wrappedMyType = proxyBuilder.Wrap(myType, new MyInterceptor()); 
wrappedMyType.Property = "Test2"; 

Могу ли я что-то упустил?

EDIT:

О боже, это, конечно, должен быть wrappedMyType. Большая ошибка. Сожалею. :(

+0

Я не знаю, возможно ли это, но мне кажется, что это довольно сложно на статически типизированном языке. – rossipedia

+0

вы не можете, вот почему: http://kozmic.pl/archive/2009/12/02/castle-dynamic-proxy-faq-why-therersquos-no-ldquoclass-proxy-with.aspx –

+0

@ Krzysztof I скорее всего, имеет прокси-генератор, который заставляет меня отмечать все «более видимым», чем защищенные как виртуальные, чем потерять возможность обертывания существующих объектов. –

ответ

3

Это не работает так, это не меняет исходный объект в любом случае.

Думай о нем, как это. Давайте рассмотреть вопрос о переходе в Китай, и работать для китайской компании, что будет платить вашу зарплату только китайскому банковскому счету в китайском банке.

Итак, вам нужно получить банковский счет в Китае. Проблема в том, что банк, который вы хотите использовать, не говорит по-английски, поэтому у вас есть проблема

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

Фактически вы можете теперь что-то сделать по линии связи, разговаривая с вашим банком.

Однако, это не означает, что ваши сотрудники банка говорят по-английски.

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

Но если вы обойдете прокси-объект, ничего не изменилось.

+0

+1 для языка/банковской аналогии :) – Jan

+0

Извините, допустил ошибку в моем примере кода, который полностью меняет смысл. :( –

+0

Это нормально, но теперь я не понимаю вопроса. Именно то, что вы хотите, и что это не так, или происходит? –

0

Возможно, вы можете сделать это с помощью System.Reflection.Emit.TypeBuilder, но это будет нелегко и, вероятно, не будет работать на всех типах. Например, вы не могли сделать это на запечатанных типах, потому что для поддержания возможности использовать свой тип обычно вам нужно было бы наследовать от него в том типе, который вы создаете, и вам придется либо переопределить, либо затенять каждое свойство в базовом классе , Кроме того, вам придется испускать IL в тело методов набора свойств, когда вы переопределяете его, чтобы поднять событие или что-то еще.

Все это возможно, но не легко и не идеально. Вероятно, вам будет лучше с другим решением. Мне нравится этот материал, хотя, может быть, если я получу какое-то время, я обновлю этот ответ с помощью образца кода (Извините, что я досуга «работаю»).

Обновление: Чем больше я думаю об этом, этого не произойдет. Возможно, если объекты, которые вы пытаетесь обернуть, всегда реализуют интерфейс, и вы хотите только перехватить эти элементы. Я подумал о публикации образца для этого, но я думаю, что это загрязнило бы этот вопрос. Лучший сценарий, который вы закончите в ситуации, описанной в ответе Джейсона.

1

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

Think следующего простого примера:

abstract class AbstractPerson { 
    public int Age { get; protected set; } 
    public abstract void Birthday(); 
} 

class Person : AbstractPerson { 
    public Person(int age) { Age = age; } 
    public override Birthday() { Age++; } 
} 

Давайте предположим, что мы хотим создать прокси-сервер для AbstractPerson перехвата Birthday.

class PersonProxy : AbstractPerson { 
    readonly AbstractPerson wrappedPerson; 

    public PersonProxy(AbstractPerson person) { 
     wrappedPerson = person; 
    } 
    public override void Birthday() { 
     DoInterceptors(); 
     wrappedPerson.Birthday(); 
    } 
    public void DoInterceptors() { 
     // do interceptors 
    } 
} 

Обратите внимание, что мы не можем переопределить Age, потому что он не отмечен как virtual. Это где противное состояние несогласованность будет поступать от:

Person knuth = new Person(71); 
PersonProxy proxy = new PersonProxy(knuth); 
Console.WriteLine(knuth.Age); 
knuth.Birthday(); 
Console.WriteLine(knuth.Age); 
Console.WriteLine(proxy.Age); 

Это напечатает

71 
72 
0 

на консоль. Что случилось? Поскольку Age не отмечен как виртуальный, наш прокси-объект не может переопределить базовое поведение и вызвать wrappedPerson.Age. В этом примере даже показано, что добавление Age = wrappedPerson.Age к конструктору для PersonProxy не поможет. Наш прокси-сервер не является прокси-сервером. Вот почему вы не можете обернуть существующие объекты.

+0

Не соответствует ли ваш пример подмножеству существующих объектов? Почему бы не отклонить объекты прокси, соответствующие вашему примеру, и разрешить проксирование для всех остальных случаев? –

0

PostSharpможет может использоваться для вас, в зависимости от того, что вы хотите делать с «перехватом», и если вы можете изменить исходный код.

Чтобы это было жизнеспособным вариантом, вы должны иметь возможность добавлять атрибуты к исходным свойствам, которые вы хотите перехватить. (Я предполагаю, что это не вариант в вашем случае, но не могу точно сказать.) Если вы в состоянии сделать это, вы можете создать атрибут (полученный из OnMethodBoundaryAspect), который может установить «ReturnValue» и «FlowBehavior», так что вы действительно перехватили вызов.