Какой самый простой способ перехватить вызов метода для дополнительной функциональности? - PullRequest
6 голосов
/ 21 декабря 2010

Предположим, у меня есть хранилище, которое возвращает список Post с. Интерфейс хранилища имеет метод GetAll(), который делает то, что предлагает.

Теперь, в соответствии с теорией, согласно которой я не должен помещать доменную логику в хранилище, я хочу перехватывать вызовы конкретного метода GetAll(), чтобы я мог добавить следующую логику к результату GetAll():

return GetAll().OrderByDescending(p => p.Posted).ToList();

Причина, по которой я хочу перехватить это, заключается в том, что (1) я не хочу, чтобы клиент не забывал вызывать метод расширения (OrderByDescending или какую-то бесполезную оболочку этого), я хочу, чтобы он вызывался каждый раз и ( 2) я не хочу, чтобы все мои конкретные реализации помнили, чтобы упорядочить результат GetAll() - я хочу эту логику в одном месте, внешнем по отношению к любому хранилищу.

Какой самый простой способ сделать это?

Я уже использую StructureMap , поэтому, если я смогу перехватить это, это может быть недорогой вариант. Но я не думаю, что SM перехватывает вызовы методов, просто создание экземпляра объекта?

Нужно ли мне переходить на прокси или миксин ? Нужно ли мне идти ва-банк с Castle Dynamic Proxy ? Или есть другой метод , который я должен рассмотреть, или, возможно, комбинация?

Я действительно заинтересован в конкретном предложении моего конкретного примера выше. Я новичок в АОП, поэтому, пожалуйста, будьте осторожны.

Ответы [ 4 ]

12 голосов
/ 23 декабря 2010

Пошёл с опцией DynamicProxy .Использовать его было проще, чем я думал.

Все, что потребовалось, это using Castle.DynamicProxy; ссылка ...

Немного IInterceptor ...

public class PostRepoInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();

        if (invocation.Method.Name.Equals("GetAll", StringComparison.InvariantCultureIgnoreCase))
            invocation.ReturnValue = this.GetModifiedGetAllResult(invocation.ReturnValue);
    }

    private object GetModifiedGetAllResult(object getAllResult)
    {
        return Post.GetOrderedPosts((IList<Post>)getAllResult);
    }
}

Две новые строки в конфигурации StructureMap:

    public RepoRegistry()
    {
        var pg = new ProxyGenerator();

        For<IPostRepository>()
            .EnrichAllWith(z => pg.CreateInterfaceProxyWithTarget<IPostRepository>(z, new PostRepoInterceptor()));
    }

.. и все готово.GetAll() теперь ведет себя так, как я хочу.Я все еще могу использовать интерфейсы, как я знаю, и я сохранил все это СУХОЙ и отделен для DDD.

Благодаря Сэм и Андре .

2 голосов
/ 21 декабря 2010

AFAIK, StructureMap только перехватывает построение объекта, поэтому с его помощью это не сработает.

Я не знаю Касла, но я думаю, что идея - здесь - это применить Шаблон декоратора , так что вы также можете сделать это самостоятельно, не возвращаясь в стороннюю библиотеку, выполнив шаги описано в предыдущей ссылке.

Вот как я это сделаю, так как я не большой поклонник АОП.

НТН

0 голосов
/ 18 января 2011

Нет, это не может изменить возвращаемое значение.Однако вы можете получить доступ к цели внутри аспекта, чтобы изменить свойство цели.Предполагая, что вы уже определили репозиторий, вот код для добавления аспекта постобработки для изменения целевого свойства.

IRepository<decimal> Rep = new Repository();
IRepository<decimal> tpRep = (IRepository<decimal>)ObjectProxyFactory.CreateProxy(Rep,
new String[] { "GetAll" },
null,
new Decoration((x, y) =>
{
    Console.WriteLine("Entering " + x.GetType().ToString());
    if (x.GetType().ToString() == "ThirdPartyHR.Repository")
    {
        List<decimal> decimals = ((Repository)x).RepList;
        IEnumerable<decimal> query = decimals.OrderByDescending(num => num, new SpecialComparer()).ToList<decimal>();
        ((Repository)x).RepList = (List<decimal>)query;
    }
}, null));
tpRep.GetAll();
List<decimal> lstRep = Rep.RepList;

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

0 голосов
/ 15 января 2011

Есть статья Добавление аспектов к объекту с использованием динамического декоратора .

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

...