Первый ограничивает T в классе, который является типом, который является производным или реализует данный интерфейс.
Если у вас есть
class Foo : ISomeInterface { }
class Bar : ISomeInterface { }
class Baz { }
С первым определением, вы бы тогда быть в состоянии построить общий экземпляр с первыми двумя типами, а не третьим.
public class SomeClass<T> where T : ISomeInterface // your definition
var obj1 = new SomeClass<Foo>();
var obj2 = new SomeClass<Bar>();
var obj3 = new SomeClass<Baz>(); // not legal, Baz does not implement ISomeInterface
Во-вторых, все, что вы сделали, - это объявление параметра типа, имеющего то же имя, что и интерфейс. Это не общее определение класса, которое работает только с интерфейсом, оно не ограничено интерфейсом, это просто путаное имя. Все три класса выше могут использоваться как аргумент типа.
public class SomeClass<ISomeInterface> // your definition
var obj1 = new SomeClass<Foo>();
var obj2 = new SomeClass<Bar>();
var obj3 = new SomeClass<Baz>(); // legal, there is no constraint
Edit: Из комментариев ниже
Я тест "var obj3 = new SomeClass<Baz>();
", и это работает, но я не понимаю, почему. Я думаю, что не понимаю этого утверждения: «Во-вторых, все, что вы сделали, - это объявить параметр типа, который имеет то же имя, что и интерфейс».
Когда вы объявляете общее определение класса public class Blah<T>
, то T
является заполнителем. Это параметр типа, который будет заполнен позже. В вашей второй версии public class SomeClass<ISomeInterface>
, ISomeInterface
- это имя заполнителя! Он не является интерфейсом, он не ограничивает класс использованием ISomeInterface
, он просто использует то же имя, что и имя параметра типа. Аргумент типа может быть любым. Это аргумент , который заполняет местозаполнитель. var foo = new SomeClass<string>()
. Здесь общий параметр был заполнен string
.
Вы заполняете в аргументе, делая то, что я делал раньше, просто создавая экземпляр
var instance = new SomeClass<string>();
Или вы можете заполнить его, используя родовой в качестве базового типа для другого типа.
class AppleSomeClass : SomeClass<Apple>
Дело в том, что это конвенции использовать T в одной ситуации типа параметра, но это только конвенции. T вместо этого можно назвать что угодно. У. X. Яблоко. Вы обнаружили, что вы также можете назвать его тем же, что и существующий тип, что, к сожалению, привело к вашей путанице здесь.
Оригинальный ответ продолжал
С ограничениями, вы можете ограничить параметр типа для класса или метода имеют определенные свойства к нему. Например, вы можете ограничить его ссылочным типом или типом значения.
where T : class // reference type
where T : struct // value type
Вы можете указать, что он должен быть унаследован от класса или реализовать интерфейс
where T : Foo // derives from Foo
where T : IFoo // implements IFoo
И вы можете потребовать, чтобы он имеет конструктор без параметров
where T : new()
И вы можете сопоставить эти , в порядке, указанном выше. Ограничение класса или структуры должно быть первым, за которым следует базовый тип или интерфейс, и, наконец, конструктор.
where T : class, IFoo
where T : class, new()
where T : class, Foo, new()
возможно дубликат [Что это C# синтаксис в виду?] (Http://stackoverflow.com/questions/2739859/what-does-this-c-sharp-syntax-mean), [C#, где ключевое слово ] (http://stackoverflow.com/questions/2774041/c-sharp-where-keyword) –
@CodyGray Вы проголосовали за закрытие этой второй ссылки в своем комментарии. Вы действительно должны иметь заинтересованность в ограничениях 'Where' или общих типах. –
@Chase: Я просто сделал, да, потому что это дубликат другого вопроса, который я нашел. Я заинтересован в уменьшении избыточности и дублирования. Это облегчает поиск ответов, которые вы ищете. –