Ответ 1
Я рекомендую избегать типичных типов, в которых работает не общий синтаксис, например, приведенный вами пример. Однако есть и другие полезные случаи.
Например, указывая тип возврата в общем случае:
static T Create<T>() where T: Sample, new()
{
return new T();
}
// Calling code
Sample sample = Create<Sample>();
вместо
static object Create()
{
return new Sample();
}
// Calling code
Sample sample = (Sample) Create();
Вы также можете использовать шаблоны для установки нескольких ограничений на тип. Например:
static T Create<T>() where T: IMyInterface, new()
{
return new T();
}
interface IMyInterface {}
class MyClass : IMyInterface { }
// Calling code.
MyClass myClass = Create<MyClass>();
Это позволяет генерировать новый тип, который реализует определенный интерфейс и имеет общий конструктор. Также:
static void DoSomething<T>(T t) where T: IMyInterface1, IMyInterface2
{
t.MethodOnIMyInterface1();
t.MethodOnIMyInterface2();
}
interface IMyInterface1
{
void MethodOnIMyInterface1();
}
interface IMyInterface2
{
void MethodOnIMyInterface2();
}
class MyClass: IMyInterface1, IMyInterface2
{
// Method implementations omitted for clarity
}
// Calling code
MyClass myclass'
DoSomething(myclass); // Note that the compiler infers the type of T.
Если вы можете потребовать несколько интерфейсов по одному параметру без (1) создания нового типа, который реализует все эти интерфейсы, и (2) требующих наличия параметров этого типа.
Как отмечает @dcastro в своем ответе, общие типы также могут сказать, что компилятор требует, чтобы типы были одинаковыми. Например:
static void DoSomething<T>(T t1, T t2) where T: MyType
{
// ...
}
class MyType {}
class MyType1: MyType {}
class MyType2: MyType {}
// Calling code
MyType1 myType1;
MyType2 myType2;
DoSomething<MyType>(myType1, myType2);
Если компилятор требует, чтобы t1 и t2 были одного типа, но могут быть любыми типами, наследующими MyType
. Это полезно в системах автоматизированного модульного тестирования, таких как NUnit или MSTest, для общих проверок равенства и сравнения.