C # - Интерфейсы / Абстрактный класс - обеспечить событие на метод - PullRequest
7 голосов
/ 07 июля 2010

У меня есть интерфейс, определенный как IStore, с двумя методами:

public interface IStore<TEntity>
{
    TEntity Get(object identifier);
    void Put(TEntity entity);
}

Я хочу, чтобы мероприятие было посвящено успеху Пут (для справки, Put может хранить строку в БД или файл в файловой системе и т. д.)

Итак, класс, реализующий Istore для типа Product, будет выглядеть примерно так:

class MyStore : IStore<Product>
{
    public Product Get(object identifier)
    {
        //whatever
    }

    public void Put(Product entity)
    {
        //Store the product in db
        //RAISE EVENT ON SUCCESS
    }
}

То, что я хочу, это способ гарантировать, что каждая реализация IStore вызывает событие - должен ли я иметь абстрактный класс или интерфейс?

Ответы [ 7 ]

9 голосов
/ 07 июля 2010

мое предложение:

public abstract class Store<TEntity>
{
    public abstract TEntity Get(object identifier);
    public void Put(TEntity entity)
    {
        //Do actions before call
        InternalPut(entity);
        //Raise event or other postprocessing
    }

    protected abstract void InternalPut(TEntity entity);
}

затем переопределите InternalPut в вашем классе

3 голосов
/ 07 июля 2010

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

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

2 голосов
/ 07 июля 2010

Вам нужно иметь абстрактный класс, реализующий метод Put из вашего интерфейса. Также вы можете добавить абстрактный метод, такой как PutImpl, примерно так:

public abstract class MyStoreBase : IStore<TEntity>
{
    public abstract TEntity Get(object identifier);

    public abstract void PutImpl(TEntity entity);

    public void Put(TEntity entity)
    {
        // Each inheritor will implement this method.
        PutImpl(entity);

        // But event is fired in base class.
        FireEvent();
    }
}
1 голос
/ 07 июля 2010

Да, вы должны использовать абстрактный интерфейс вместо интерфейса.

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

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

public abstract class AbstractStore<TEntity>
{
    public TEntity Get(object identifier);
    public sealed void Put(TEntity entity)
    {
        if (DoPut(entity))
        {
            // raise event
        }
    }

    protected abstract bool DoPut(TEntity entity);
}

Реальное хранилище должно будет реализовать метод DoPut, возвращая логическое значение, указывающее, была ли операция Put успешной.Событие будет вызвано методом Put, который является общедоступным.

0 голосов
/ 07 июля 2010

Написание абстрактного класса для переноса PutInner -подобного метода - абсолютно лучший способ приблизиться к этому, как уже предлагали другие.

Я бы просто добавил, что если вам нужна любая реализация *От 1004 * до всегда вызывать событие при вызове Put, я бы рекомендовал также добавить упомянутое событие в сам интерфейс:

public interface IStore<TEntity>
{
    event EventHandler<EntityEventArgs<TEntity>> EntityAdded;

    TEntity Get(object identifier);
    void Put(TEntity entity);
}

public EntityEventArgs<TEntity> : EventArgs
{
    public TEntity Entity { get; set; }
}

Это не force разработчикам делать что угодно;но это ясно устанавливает ожидание того, что EntityAdded будет поднят на успешном Put.

0 голосов
/ 07 июля 2010
 abstract class Store<TEntity>
{
     public abstract TEntity Get(object identifier);
     protected abstract void Put(TEntity entity);
     public void PutBase(TEntity entity)
     {
         Put(entity);
         //Raise event here
     }

}

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

0 голосов
/ 07 июля 2010

Если вам действительно нужно использовать интерфейс, то новый PostSharp 2 может выполнять наследование аспектов.К сожалению, чтобы получить эту функцию, вам нужно приобрести как минимум личную лицензию за 200 долларов.

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

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