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

#c# #.net #generics #architecture

#c# #.net #дженерики #архитектура

Вопрос:

я пытаюсь сгенерировать некоторые методы, подобные приведенным ниже, add crm и human resources . Но я хочу написать Crm, HumanResources, SupplChain и т.д. (5-6 модулей) как написать приведенные ниже коды просто (приведенные ниже коды — скелет :)) сначала я писал без дженериков, а затем я написал с дженериками. Второе использование отличается от первого. 1) Четкое чтение также управляемое и расходуемое
2) дает мне некоторые преимущества в производительности. Нет процесса упаковки и распаковки

МОЖЕТЕ ЛИ ВЫ научить меня плюсам и минусам дженериков С сравнением первого и второго использования?

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace App.GenericsBaseClass.Diff
{

    // View : 
    class Program
    {
        static void Main(string[] args)
        {
            new Crm().Add("Yapı Kredi");
            Console.Read();
            new HumanResources().Add("yusuf karatoprak");
            Console.Read();
        }
    }

  // Business
    public class Crm : Customer
    {
        public override void Add(object obj)
        {
            if (obj is String)
            {
                base.Add(obj);
            }
            else
            {
                throw new InvalidOperationException("Customer Name must be string Format...");
            }
        }
    }

    public class HumanResources : Staff
    {
        public override void Add(object obj)
        {
            if (obj is string)
            {
                base.Add(obj);
            }
            else
            {
                throw new InvalidOperationException("Stuff Name must be string Format...");
            }

        }
    }

    // Dal
    public class Staff
    {
        public virtual void Add(object obj)
        {
            new Db.Staff().Save((string)obj);
        }
    }

    public class Customer
    {
        public virtual void Add(object obj)
        {
            new Db.Customer().Save((string)obj);
        }

    }
    // Model
    public class Db
    {

        public class Customer
        {
            public void Save(string Name)
            {
                Console.WriteLine("Customer : {0} is saved",Name);
            }
        }

        public class Staff
        {
            public void Save(string Name)
            {
                Console.WriteLine("Staff: {0} is saved", Name);
            }
        }
    }
}

  
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace App.GenericsInstadofBaseMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            new Crm<string>().Add("Yapı Kredi");
            Console.Read();
            new HumanResources<string>().Add("yusuf karatoprak");
            Console.Read();
        }
    }

    // Business
    public class Crm<T> : Customer<T>
    {
        public override void Add(T obj)
        {
                base.Add(obj);
        }
    }

    public class HumanResources<T> : Staff<T>
    {
        public override void Add(T obj)
        {
                base.Add(obj);
        }
    }

    // Dal
    public class Staff<T>
    {
        public virtual void Add(T obj)
        {
            new Db<T>.Staff().Save(obj);
        }
    }

    public class Customer<T>
    {
        public virtual void Add(T obj)
        {
            new Db<T>.Customer().Save(obj);
        }

    }
    // Model

    public class Db<T> 
    {
        public class Customer
        {
            public void Save(T Name)
            {
                Console.WriteLine("Customer : {0} is saved", Name.ToString());
            }
        }

        public class Staff
        {
            public void Save(T Name)
            {
                Console.WriteLine("Staff: {0} is saved", Name);
            }
        }

    }
}

  

Комментарии:

1. Чего вы пытаетесь достичь с помощью этого использования дженериков? Мне кажется, что использовать дженерики совершенно бесполезно Name .

2. Вероятно, должно быть Customer<T> и Staff<T> вместо Db<T>

3. Если вы хотите сохранить строковое имя, сделайте так, чтобы ваш метод принимал строку. Какой смысл в создании контракта API, который вы на самом деле не можете выполнить? Вся иерархия типов запутана из-за смешения проблем с сохраняемостью с излишне глубокой иерархией наследования. Я бы рекомендовал взглянуть на приличный ORM.

Ответ №1:

Из того немногого, что я понимаю, большинство операций с дженериками выполняются на IL уровне, так что потери производительности невелики, если вообще есть. Все, что он делает, это заставляет и проверяет объекты определенного типа. Самым большим недостатком является понимание контравариантности и ковариации. Вот несколько статей об этом.

Статьи

Использование различий в интерфейсах для универсальных коллекций

Часто задаваемые вопросы о ковариации и контравариантности (обновлен .NET 4.0)

Плюсы

С дженериками вы получаете безопасность типов как во время выполнения, так и во время разработки. Вы можете получать информацию intellisense о своих объектах в режиме реального времени, как если бы они были жестко запрограммированы для определенного типа. Это очень полезно при настройке обоих методов расширения, и …ну, почти все остальное. Фактически, начиная с .NET 2.0, я даже не обнаруживаю, что использую не-универсальные списки для чего-либо еще, если только тип не является просто object

  • Редактировать

Как указывали другие, это предотвращает необходимость распаковки.

Минусы

Из-за разной природы контраргументации и ковариации иногда может возникнуть путаница в отношении того, что приемлемо, а что нет в дженерике. Например, если вы рассмотрите следующий макет ..

 interface IBase {
}

class Alpha : IBase {
}

class Beta : Alpha {
}

IList<IBase> ListOfObjects { get; set; }
  

Это сбивает с толку. Можете ли вы передать оба Alpha и Beta объекты в список? Когда я попробовал это, вы не смогли. Но тогда сработало следующее..

 IList<Alpha> ListOfObjects { get; set; }
  

Он принимал как Alpha , так и Beta объекты, потому что Beta наследует Alpha

Взгляните на дополнительную информацию о контравариантности и ковариации здесь. Это очень полезно.

Я никогда не замечал снижения производительности от дженериков. Однако это не означает, что их не существует. Однако это всего лишь обычные объекты, поэтому я не вижу, где могут быть накладные расходы. В общем случае компилятор не должен даже разрешать вам запускать код, в котором вы пытаетесь добавить неподходящие объекты в общий список, и если это происходит, то вы где-то допустили ошибку разработчика, или используете dynamics , или столкнулись с проблемой контравариантности или ковариантности. Хотя я понимаю, что кое-что из этого изменилось с .NET 4.0.

Комментарии:

1. на самом деле не все так похоже на шаблоны. И что вы подразумеваете под «старым кодом C «?

2. Разница в терминологии. Профессора моего колледжа давным-давно показали нам кое-что на C , что функционировало немного похоже на дженерики, и назвали их шаблонами. Я не пишу на C , поэтому я не знаю фактического термина. Я должен был быть более конкретным — честно говоря, я даже не помню этого достаточно, чтобы понять, почему я поместил туда этот комментарий. В принципе, вы могли бы создать класс, который мог бы принимать любой тип и выполнять определенные операции над ними, независимо от типа.

Ответ №2:

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

 public class Person {
   public string Name { get; set; }
}
public class Customer : Person {

}
public class Staff : Person {
}

public class HumanResources : Staff {
}

public class Db {
  public List<Customer> Customers { get; set; }
  public List<Staff> Staff { get; set; }
}

public static void Main(){ 
  var db = new Db {
     Customers = new List<Customer> { },
     Staff = new List<Staff> { }
  };

  Db.Customers.Add(new Customer { Name = "Primary Customer" } );
  Db.Staff.Add(new Staff { Name = "Employee Prime" } );
  Db.Staff.Add(new HumanResources { Name = "Human Resource Manager" });
}
  

Дженерики следует использовать для указания вводимого типа, а не для фактического управления данными. В приведенном вами примере дженерики используются не по назначению.

В этом примере вы создаете базовый класс, а затем три подтипа, один из которых наследуется от другого подтипа. Итак, у вас есть Customer и Staff в качестве двух основных типов, которые принимает Db , (предполагая, что это сокращение от database).

Db Может содержать список Customer s и список Staff , поскольку HumanResources это тип Staff , вы можете хранить их вместе. Вы также могли бы добавить List<Person> People { get; set; } , и он принимал бы все типы, поскольку они неизбежно наследуются друг от друга.

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

 public class Person { 
   public Person(string name) { 
      this.Name = name; }
   }

   public string Name { get; private set; }
}
  

В этом примере мы настраиваем Name поле таким образом, чтобы его могли видеть все, но только изменяли и устанавливали при создании (не совсем лучшая идея, но это демонстрирует суть).

Итак, теперь вы бы добавили новый, Customer подобный этому ..

Db.Customers.Add( new Customer ( "Ciel" ) ); или новый персонал … Db.Staff.Add( new Staff( "Darin" ) ); .

Ответ №3:

Я не думаю, что разница в производительности существенна.

Что вы действительно получаете, используя дженерики, так это проверку типов во время компиляции. Например, это может помешать вам передать объект неправильного типа (использование object параметра в этом случае привело бы к ошибкам во время выполнения, если вы ожидаете определенный тип).

Комментарии:

1. Дженерики позволяют избежать боксирования для типов значений, тогда как использование object принудительно блокирует.

2. Я добавлю, что дженерики создают статические версии методов во время компиляции, а не во время выполнения. Таким образом, не должно быть никакого влияния на производительность.

Ответ №4:

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

Боксирование — это бонус, но вы не должны выбирать дженерики только для того, чтобы избежать боксирования (что звучит как преждевременная оптимизация).

Ответ №5:

Здесь вы можете найти очень интересное видео о преимуществах и недостатках использования дженериков.