C# - Интерфейсы / Абстрактный класс - гарантирует, что событие генерируется на методе

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

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

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

Так, реализация класса Istore для типа продукта немного походила бы на это:

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
задан Alex 7 July 2010 в 12:19
поделиться

7 ответов

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

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 в вашем классе

9
ответ дан 6 December 2019 в 14:00
поделиться

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

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

3
ответ дан 6 December 2019 в 14:00
поделиться

Вам нужно иметь абстрактный класс, реализующий метод 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();
    }
}
2
ответ дан 6 December 2019 в 14:00
поделиться
 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 как protected, так что все производные классы должны реализовать его, но клиентский код не может вызвать его.

0
ответ дан 6 December 2019 в 14:00
поделиться

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

Я бы просто добавил, что если вы хотите, чтобы любая реализация IStore в всегда вызывала событие, когда вызывается 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; }
}

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

0
ответ дан 6 December 2019 в 14:00
поделиться

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

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

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

Я думаю, что лучшим методом будет использование шаблонного метода :

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, который является общедоступным.

1
ответ дан 6 December 2019 в 14:00
поделиться

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

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

0
ответ дан 6 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: