Генерировать перехватывающий прокси из конкретного класса? - PullRequest
5 голосов
/ 21 мая 2011

Мне нужно создать прокси, который перехватывает свойства в классе.Я знаю, как создать динамический прокси с Emit из интерфейса, но что если у меня нет интерфейса?Я видел примеры, которые используют RealProxy (например, такой: . Есть ли способ вызвать метод, когда установлено какое-либо свойство класса? ), но возможно ли использовать генерацию типа и команду emit для достижениято же самое?Я не хочу, чтобы "владелец" конкретного класса видел какие-либо следы MarshalByRefObject, если это возможно (см. Ниже) ...

Я считаю, что Касл способен сделать это, но, возможно, он использует RealProxy подчехлы?

User user = Create<User>();

public class User
{
    public string Name { get; set; } 
}

public T Create<T>()
{
    //magic happens here... :)
    return (T)GenerateInterceptingProxyFromT(typeof(T));
}

Ответы [ 3 ]

0 голосов
/ 21 мая 2011

Я только начал возиться с postshrp , одним из инструментов АОП, упомянутых Мигелем, функционально делать то, что вы пытаетесь делать. Он использует «статическое переплетение» для внедрения кода во время компиляции, поэтому должен быть невидимым для потребителей. Очевидно, вам нужно изменить код, который вы хотите, чтобы инструмент работал, чтобы это работало.
Ответ на Этот вопрос предлагает использовать API профилировщика, который может быть вам полезен, если PostSharp или Castle не будут делать то, что вам нужно.

0 голосов
/ 23 мая 2011

Поскольку это очень распространенная проблема и хорошая причина выбрать подход AOP, как предложил Мигель, я создал пример для Afterthought , который демонстрирует реализацию INotifyPropertyChanged (перехватывает наборы свойств ввызвать событие).

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

public override void Amend<TProperty>(Property<TProperty> property)
{
    // Raise property change notifications
    if (property.PropertyInfo.CanRead && property.PropertyInfo.CanWrite)
        property.AfterSet = NotificationAmender<T>.OnPropertyChanged<TProperty>;
}

, который в этом случае вызывает статический метод OnPropertyChanged, который выглядит следующим образом:

public static void OnPropertyChanged<P>(INotifyPropertyChangedAmendment instance, string property, P oldValue, P value, P newValue)
{
    // Only raise property changed if the value of the property actually changed
    if ((oldValue == null ^ newValue == null) || (oldValue != null && !oldValue.Equals(newValue)))
        instance.OnPropertyChanged(new PropertyChangedEventArgs(property));
}

Так что если вашИсходное свойство выглядело так:

string name;
public string Name 
{
    get
    {
        return name;
    }
    set
    {
        name = value;
    }
}

Это будет выглядеть после применения вышеуказанной поправки с помощью Afterthought:

string name;
public string Name 
{
    get
    {
        return name;
    }
    set
    {
        string oldValue = Name;
        name = value;
        NotificationAmender<ConcreteClass>.OnPropertyChanged<string>(
            this, "Name", oldValue, value, Name);
    }
}

В вашем случае статический метод вызывается после (или до)сеттер может быть назван как угодно и делать что угодно.Это всего лишь пример конкретной и хорошо известной причины перехвата установщиков свойств.Учитывая, что вы знаете, что свойства не виртуальные, невозможно создать прокси-подклассы для выполнения перехвата, поэтому я думаю, что AOP-подходы, такие как Afterthought или PostSharp, - ваш лучший выбор.

Кроме того, с Afterthought вы можетереализуйте перехват таким образом, чтобы у получающихся сборок не было никаких ссылок или зависимостей от Afterthought, и если ваша логика перехвата фактически не добавляет / не изменяет API для ваших целевых типов, нет никакой причины, по которой «владелец» конкретного класса имел быпроблема с результатом.

0 голосов
/ 21 мая 2011

В .Net есть несколько вариантов перехвата вещей:

  • Если это интерфейс, вы можете динамически реализовать новый тип из этого и создать прокси, который будет-вызовите другой внутренний объект.

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

  • Если тип, который вы хотите перехватить, не имеет интерфейсов, переопределенных методов или свойств, то перед загрузкой необходимо изменить сборку, которая содержит этот тип.Вы не можете изменить код сборки после ее загрузки.Я думаю, что PostSharp работает таким образом.

Большинство инструментов для насмешек , используемых в целях тестирования, используют первую / вторую альтернативы, но это заставляет их работать только счлен классов, которые могут быть переопределены или реализованы через интерфейс.

Аспектно-ориентированное программирование * Инструменты 1022 * используют третью альтернативу, но это больше работы, потому что вам нужно обработать сборкудо его загрузки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...