2012-06-14 4 views
5

Вот общий класс я работаю с:C# Бетон переопределение родового класса

public interface IRepository<T> where T : EntityObject 
{ 
    RepositoryInstructionResult Add(T item); 
    RepositoryInstructionResult Update(T item); 
    RepositoryInstructionResult Delete(T item); 
} 
public class Repository<T> : IRepository<T> where T : EntityObject 
{ 

    RepositoryInstructionResult Add(T item) 
    { //implementation} 
    RepositoryInstructionResult Update(T item); 
    { //implementation} 
    RepositoryInstructionResult Delete(T item); 
    { //implementation} 
} 

Теперь я смотрю изредка изменять поведение методов при т: конкретный тип. Возможно ли следующее: Эта конкретная попытка дает ошибку (ошибка 5: частичные объявления «репозитория» должны иметь одинаковые имена параметров типа в том же порядке).

public class Repository<Bar> //where Bar : EntityObject 
{ 
    RepositoryInstructionResult Add(Bar item) 
    { //different implementation to Repository<T>.Add() } 
    //other methods inherit from Repository<T> 
} 
+2

'BarRepository: Repository ...', и отметьте augmentible методы, как виртуальный/переопределить в базовых/дочерних классов, соответственно. –

+0

@ Энтони: Почему бы не опубликовать это как ответ? (Который я собирался опубликовать = P) – benjer3

ответ

4
public class BarRepository : Repository<Bar> 
{ 
    RepositoryInstructionResult Add(Bar item) 
    { //different implementation to Repository<T>.Add() } 
    //other methods inherit from Repository<T> 
} 
+1

Мое возражение против этого решения заключается в том, что вам нужно принудительно инициализировать 'new BarRepository()' явно. Если вы вызываете 'новый репозиторий ()', вы получаете общую (то есть неправильную) реализацию. Поскольку Хранилища уже создаются и потребляются по моей кодовой базе, я бы предпочел не скрывать instanciation на заводе. – daveharnett

+0

Этот код, очевидно, нуждается в том, чтобы методы отображались как общедоступные для выполнения интерфейса и нуждались в модификаторах virtual/override в основе/child, чтобы полиморфно использовать поведение. –

+0

@ daveharnett, чтобы лучше всего использовать шаблон репозитория, код или логика, зависящая от репозитория, будет кодировать интерфейс вместо реализации. Тогда этот код будет смотреть на «IRepository » и, следовательно, его не нужно будет менять. Хотя вы правы, любой код, отвечающий за создание конкретных реализаций, нуждается в обновлении. –

0

Имя Ваш Repository класс RepositoryBase и сделать методы интерфейса виртуальной. реализовать их в общем виде внутри вашего класса RepositoryBase, но поскольку u отмеченные методы как виртуальные u смогут переопределять функциональность в ваших производных классах, ваш код будет выглядеть примерно так.

public interface IRepository<T> where T : EntityObject 
{ 
    RepositoryInstructionResult Add(T item); 
    RepositoryInstructionResult Update(T item); 
    RepositoryInstructionResult Delete(T item); 
} 

public class Repository<T> : IRepository<T> where T : EntityObject 
{ 
    virtual RepositoryInstructionResult Add(T item) 
    { //implementation} 
    virtual RepositoryInstructionResult Update(T item); 
    { //implementation} 
    virtual RepositoryInstructionResult Delete(T item); 
    { //implementation} 
    } 

Если U нужны некоторые пользовательские логик должны быть выполнен для метода обновления для Bar объект просто создать производный класс Названия этого BarRepository и метод обновления переопределения класса Repositorybase здесь у может либо вызов реализации базовой или просто процесс с его собственная логика

public class BarRepository : Repositorybase<Bar> 
{ 
    public override RepositoryInstructionResult Update(Bar item); 
    { 
     //Call base method if needed 
     //Base.Update(item); 

     //implement your custom logic here 
    } 
    } 
+0

То же самое, что и мой ответ. Он выполнит свою работу, но это усложнит потребление. – daveharnett

+0

Что вы подразумеваете под этим? –

+0

Я имел в виду, что вам нужно принудительно инициализировать 'new BarRepository()' явно. Если вы вызываете 'новый репозиторий ()', вы получаете общую (то есть неправильную) реализацию. В идеале я искал решение, которое будет скрыто от кода создания репозитория. – daveharnett

0

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

if (typeof(T) == typeof(Bar)) { 
    // your Bar-specific code 
} 
// ... 

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

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

+0

Спасибо. Производительность в стороне, это было бы очень грязно, если бы было несколько особых случаев. – daveharnett

+0

@ daveharnett: Не обязательно; в этом случае вы можете использовать «Словарь <Тип, Обработчик>' объектов 'Handler' (собственный класс), которые выполняют действия типа. Таким образом, это всего лишь три-четыре строки кода (возможно, меньше с помощью метода расширения) в каждом методе, который нуждается в специальном лечении. –

0

использовать метод расширения:

public static void DoSomething(this repository<Bar> repo) 
{ 
    //your custom code goes here 
} 
Смежные вопросы