Самые важные вещи о С# generics... извлеченные уроки
Что самое важное, что вы знаете о дженериках: скрытые функции, распространенные ошибки, лучшие и полезные методы, советы...
Я начинаю реализовывать большую часть своей библиотеки /API с помощью дженериков и собираюсь собирать наиболее распространенные шаблоны, советы и т.д., которые можно найти на практике.
Позвольте мне оформить вопрос: что самое главное, что вы узнали о дженериках?
Попробуйте привести примеры - было бы проще понять, в отличие от запутанных и чрезмерно сухих описаний
Спасибо
Этот вопрос несколько похож на вопрос Jon, хотя на другой предмет.
Ответы
Ответ 1
Одна из самых важных вещей, которые я узнал, заключается в том, что вы можете ограничить параметры типового типа. Это может быть очень мощным, позволяя вам настроить класс только для определенных типов объектов и позволить вам использовать членов этого типа в вашем общем классе. Я понимаю, что это довольно фундаментально, но это одна из вещей, которая делает дженерики невероятно полезными.
Ответ 2
Каждая специализация родового типа рассматривается как уникальный тип, когда речь идет о таких вещах, как статические члены. Например, с этим типом:
class GenericType<T>
{
public static int SomeValue;
}
Утверждение выполняется, если мы это сделаем:
GenericType<int>.SomeValue = 3;
Debug.Assert(GenericType<double>.SomeValue == 0);
Это происходит потому, что:
typeof(GenericType<int>) != typeof(GenericType<double>)
Даже если
typeof(GenericType<int>.GetGenericTypeDefinition() == typeof(GenericType<double>).GetGenericTypeDefinition()
Ответ 3
Понимать возможности и ограничения вывода типового типа в С#. Глубокое понимание того, что компилятор может и не может сделать, исходя из (например) типов параметров в вашем методе, можно использовать, чтобы сделать обычные случаи использования вашего API значительно более удобочитаемыми.
Ответ 4
Самый важный урок о дженериках, которые я узнал: чем больше вы их используете, тем лучше.
Ответ 5
Нет ковариации или contra-variance (по крайней мере, в 3.5). Помните об этом при разработке иерархии классов, которые включают параметры типового типа.
Ответ 6
Два интересных урока. Первый; со списками; попытайтесь думать в терминах T
; подробнее см. здесь, но вкратце вам нужно использовать:
public void Foo<T>(IList<T> data) where T : SomeBaseClassOrInterface {}
и не:
public void Foo(IList<SomeBaseClassOrInterface> data) {}
Второе: следить за краевыми случаями;-p
Вы можете увидеть ловушку здесь?
static void Foo<T>() where T : new()
{
T t = new T();
Console.WriteLine(t.ToString()); // works fine
Console.WriteLine(t.GetHashCode()); // works fine
Console.WriteLine(t.Equals(t)); // works fine
// so it looks like an object and smells like an object...
// but this throws a NullReferenceException...
Console.WriteLine(t.GetType()); // BOOM!!!
}
Ответ 7
Не знаю, важны ли они, но я узнал следующее:
Дженерики будут доступны только через отражение, если вы не знаете тип фриккина. В некоторых случаях вам могут понадобиться не общие интерфейсы для использования ваших общих классов в ситуациях, когда тип неизвестен.
Я чуть не сорвал голову, пока не почувствовал, что
public class Foo<T> where T : Foo<T> {
public T CloneMe() ...
}
является вполне допустимым кодом и позволяет вашему базовому классу выставлять методы и свойства, относящиеся к специализированному классу..., который оказался в определении конечного автомата по его состояниям:
public abstract class Machine<S,M> where S : State<S,M> where M : Machine<S,M> {
protected S state;
}
public abstract class State<S,M> where S : State<S,M> where M : Machine<S,M> {
protected M machine;
}
Дженерики могут стать немного громоздкими. На днях у меня было это:
List<Tuple<Expression<Func<DataTable,object>>,Expression<Func<DataTable,object>>>>
уф...
Ответ 8
MyGeneric<T> where T : IComparable
не делает
MyGeneric<IComparable>
базовый класс.
Ответ 9
Я узнал, что дженерики являются мощным инструментом indeep, но неправильно используются, что приводит к очень нечитаемому коду.
Ответ 10
Прежде всего, важно знать, как работают Generics в С#. Эта статья дает вам хороший обзор дженериков Андерса Хейлсберга (отцом С#). Я не думаю, что использовать их как можно чаще - это хорошо. Используйте дженерики, когда они действительно имеют смысл. Всегда помните KISS и YAGNI (Keep It Simple Stupid, вам это не понадобится) от экстремального программирования.
Ответ 11
Общие типы делегатов всегда являются инвариантами типа.
Я столкнулся с проблемой, подобной той, что описана в ссылке ниже дня, и это вызвало некоторую путаницу, потому что я не понимал, почему мне пришлось снимать свою коллекцию.
http://www.theserverside.net/blogs/thread.tss?thread_id=47323