Это хороший способ выставить универсальные методы базового класса через интерфейс? - PullRequest
0 голосов
/ 09 апреля 2010

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

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

Вот простая версия единственного способа, которым я могу видеть, чтобы заставить его работать в данный момент.

public interface IFoo
{
    void Process(Bar_base bar);
}

public abstract class FooBase<T> : IFoo 
    where T : Bar_base
{
    abstract void Process(T bar);

    // Explicit IFoo Implementation
    void IFoo.Process(Bar_base bar)
    {
        if (bar == null) throw new ArgumentNullException();

        // Downcast here in base class (less for subclasses to worry about)
        T downcasted_bar = bar as T;
        if (downcasted_bar == null)
        {
            throw new InvalidOperationException(
                          string.Format("Expected type '{0}', not type '{1}'",
                                        T.ToString(), bar.GetType().ToString());
        }

        //Process downcasted object.
        Process(downcasted_bar);            
    }

}

Тогда подклассы FooBase будут выглядеть так ...

public class Foo_impl1 : FooBase<Bar_impl1>
{
     void override Process(Bar_impl1 bar)
     {
         //No need to downcast here!
     } 
}

Очевидно, что это не даст мне времени для проверки типов, но я думаю, что это сделает работу ...

Вопросы:
1. Будет ли эта функция работать так, как я думаю?
2. Это лучший способ сделать это?
3. Какие проблемы возникают при этом?
4. Можете ли вы предложить другой подход?

Спасибо!


Редактировать: В ответе на многие ответы требуется, чтобы IFoo не был универсальным. Мне нужно иметь возможность манипулировать коллекцией объектов IFoo независимо от универсальных типов, которые они используют.


Редактировать: чтобы выяснить причину этого ...

Bar_base содержит ссылку на тип IFoo. И должен вызвать метод процесса для проверки данных, которые он содержит. Думайте об IFoo как об объекте, который содержит логику проверки для производных объектов Bar_base. Когда вопрос о достоверности объекта Bar_base ставится под сомнение, он вызывает Process для своей ссылки IFoo для проверки себя.

Причина, по которой IFoo не может быть универсальной, заключается в том, что мне нужно иметь возможность ссылаться на коллекцию IFoo, независимую от классов Bar_base.

Я собираюсь попробовать подход с двумя интерфейсами: универсальным, содержащим метод Process, и необщим, который не содержит.

Ответы [ 4 ]

1 голос
/ 09 апреля 2010

Учитывая ваше ограничение, что T имеет тип Bar_base и (в вашем примере) использует только T для процесса (T bar), я не уверен, зачем вы вообще используете дженерики. Если

abstract Process(Bar_base bar)

- это все, что вам нужно, этого должно быть достаточно для переопределения класса с помощью

void override Process(Bar_impl1 bar)

и ваш абстрактный класс Bar_base является достаточным ограничением типа.

Если я что-то упустил ....

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

interface IFoo
{
...
}

interface IFoo<T> : IFoo where T : Bar_base
{
...
}

Но я не уверен, что это удовлетворит ваши потребности в этом случае.

1 голос
/ 09 апреля 2010

В случае, когда IFoo не может быть универсальным, в таком случае очень типично иметь два интерфейса, IFoo<T> и IFoo, где IFoo использует наиболее поддерживаемый базовый класс. Подумайте IEnumerable<T> и IEnumerable. Неуниверсальная версия обычно скрывается как перегрузка интерфейса, поэтому она вступает в действие только при доступе к классу через неуниверсальный интерфейс.

0 голосов
/ 09 апреля 2010

Любая причина, по которой вы не просто используете общий интерфейс: -

public interface IFoo<T>
  where T:Bar_base
{
    void Process(T bar);
}
0 голосов
/ 09 апреля 2010

Вы можете просто сделать IFoo универсальным:

public interface IFoo<T> where T : Bar_base
{
    void Process(T bar);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...