Дженерики против наследования (когда не участвуют классы коллекции) - PullRequest
12 голосов
/ 15 апреля 2010

Это расширение этого вопроса и, возможно, может даже быть дубликатом какого-либо другого вопроса (если так, пожалуйста, прости меня). Я вижу из MSDN , что дженерики обычно используются с коллекциями

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

Примеры, которые я видел, также подтверждают вышеприведенное утверждение.

Может ли кто-нибудь дать правильное использование обобщений в сценарии реальной жизни, который не включает какие-либо коллекции?

Педантично, я думал о создании примера, который не включает коллекции

public class Animal<T>
{
    public void Speak()
    {
       Console.WriteLine("I am an Animal and my type is " + typeof(T).ToString());
    }

    public void Eat()
    {
        //Eat food
    }
}

public class Dog
{
    public void WhoAmI()
    {
        Console.WriteLine(this.GetType().ToString());

    }
}         

и «Животное типа Собака» будет

Animal<Dog> magic = new Animal<Dog>();

Вполне возможно, что Dog будет наследоваться от Animal (при условии, что не универсальная версия Animal) Dog:Animal Следовательно, Dog является Animal

Другим примером, о котором я думал, был BankAccount. Это может быть BankAccount<Checking>, BankAccount<Savings>. Это вполне может быть Checking:BankAccount и Savings:BankAccount.

Существуют ли передовые практики, чтобы определить, следует ли нам использовать дженерики или наследование?

Ответы [ 5 ]

8 голосов
/ 15 апреля 2010

Возможно, вы получите лучшие ответы, но тем не менее подумайте об этом: Универсальные классы подразумевают отношение "of" между универсальным классом и классом параметров.

Все собаки являются животными, поэтому они имеют определенные атрибуты / качества со всеми другими животными. Если вы используете наследование, то очень легко реализовать эти общие качества в классе Animal и добавить качества в классы-потомки. Но если вы реализуете это с помощью Animal (Of Dog), то:

  1. Ваш класс Собаки сам по себе не является полностью квалифицированной собакой / животным, поскольку его "качества животных" содержатся в классе Animal (Of T). Собака должна быть связана с Животным в отношениях родитель-ребенок.
  2. Ваш класс Animal на самом деле не животное: вы не можете создать метод, который принимает Animals в качестве аргумента, потому что вы не можете ссылаться на глобализированный класс Animal (Of T). На самом деле это семейство классов с общим поведением, а не суперкласс. Вы теряете преимущество общения с животными вне класса Animal (Of T).

Но вот как, ИМХО, вы должны подумать о дженериках: Подумайте о MedicalDoctor(Of T) классе. Veterinarian(Of T as Animal) будет наследоваться от MedicalDoctor(Of Animal). DogVeterinarian будет наследоваться от Veterinarian(Of Dog).

Ключевой момент: универсальный класс и класс параметров не являются тесно связанными и взаимозависимыми, они сосуществуют.

Кстати, если вы хотите увидеть хорошее использование обобщений, не связанных с коллекцией, просто обратите внимание на имеющиеся у нас делегаты: Action (Of T), Func (Of TResult), Comparison (Of T), EventHandler (Of TEventArgs), Конвертер (Of TSource, TResult) ... и интерфейсы: IEqualityComparer (Of T), IComparer (Of T) ...

3 голосов
/ 15 апреля 2010

Nullable<T> является общим, не является классом коллекции, а не может включать наследование, поскольку относится к struct s.

Общие семейства делегатов довольно хороши - EventHandler<T>, Action<...]>, Func<[...]> - это намного более понятно, чем Func<int,bool>, а не какой-то пользовательский IdPredicate или чем-то еще. *

3 голосов
/ 15 апреля 2010

Один пример из реальной жизни, о котором известно, находится на фабрике каналов WCF .

Со страницы:

public sealed class Test
{
    static void Main()
    {
        // Code not shown.
    }

    public void Run()
    {
        // This code is written by an application developer.
        // Create a channel factory.
        BasicHttpBinding myBinding = new BasicHttpBinding();

        EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1");

        ChannelFactory<IMath> myChannelFactory = new ChannelFactory<IMath>(myBinding, myEndpoint);

        // Create a channel.
        IMath wcfClient1 = myChannelFactory.CreateChannel();
        double s = wcfClient1.Add(3, 39);
        Console.WriteLine(s.ToString());
        ((IClientChannel)wcfClient1).Close();

        // Create another channel.
        IMath wcfClient2 = myChannelFactory.CreateChannel();
        s = wcfClient2.Add(15, 27);
        Console.WriteLine(s.ToString());
        ((IClientChannel)wcfClient2).Close();
        myChannelFactory.Close();
    }
}

То, что я думаю о дженериках, это то, что они представляют тип, на который действует класс. Например, ChannelFactory создает фабрики типа T. Наследование представляет собой иерархические отношения между типами. Собака - это животное, золотистый ретривер - это и собака, и животное.

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

Вы путаете аспект наследования "is-a" с аспектом обобщений "of".

Обобщения подразумевают одинаковость операций между классами, а не только то, что операции существуют полиморфно.

В вашем примере с Animal экземпляр Animal<Dog> не имеет метода WhoAmI, тогда как экземпляр Dog : Animal будет.

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

Используйте наследование в вашей ситуации, пожалуйста.
Если класс может быть правильно описан другим классом [например, квадрат может быть описан как прямоугольник], квадрат должен наследоваться / расширяться от квеста прямоугольника. В противном случае вы попадаете в беспорядок.

Использовать GenericClass для обозначения this is a GenericClass object of tType-s Используйте Квадрат: Прямоугольник для обозначения this is a Square, which is also a Rectangle

В вашем случае:
Использовать собаку: животное означает this is a Dog, which is also an Animal

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