Подтвердить что ты не робот

Generics vs inheritance (если не задействованы классы коллекции)

Это расширение этого вопроса и, возможно, даже может быть дубликатом какого-то другого вопроса (если так, пожалуйста, простите меня). я см. Из 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 типа Собака" будет

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

Вполне возможно, что Dog наследуется от Animal (Предполагая не общий вариант Animal) Dog:Animal Поэтому Dog является Animal

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

Есть ли какие-либо рекомендации, чтобы определить, следует ли нам идти с дженериками или с наследованием?

4b9b3361

Ответ 1

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

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

  • Ваш класс Dog не является полностью полноценной собакой/животным сам по себе, так как его "свойства животных" содержатся в классе Animal (Of T). Собака должна быть привязана к животному в отношениях между родителем и ребенком.
  • Класс вашего животных на самом деле не является животным: вы не можете создать какой-либо метод, который принимает Животные как аргумент, потому что вы не можете ссылаться на глобализованный класс 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), Сравнение (Of T), EventHandler (Of TEventArgs), Конвертер (из TSource, TResult)... и интерфейсы: IEqualityComparer (Of T), IComparer (Of T)...

Ответ 2

Один пример реального мира, который знает, находится в WCF Channel Factory.

На странице:

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. Inheritance представляет иерархическую взаимосвязь между типами. Собака - это животное, золотистый ретривер - собака и животное.

Ответ 3

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

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

Ответ 4

Вы вводите в заблуждение аспект наследования "is-a" с "аспектом" дженериков.

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

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

Ответ 5

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

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

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