The first restricts T in the class to the type that outputs or implements this interface.
If you
class Foo : ISomeInterface { } class Bar : ISomeInterface { } class Baz { }
With your first definition, you could build a shared instance with the first two types, not the third.
public class SomeClass<T> where T : ISomeInterface
Secondly, all you have done is declare a type parameter that has the same name as the interface. This is not a general class definition that works only with an interface; it is not limited to an interface; it is just a confused name. All three classes above can be used as type arguments.
public class SomeClass<ISomeInterface> // your definition var obj1 = new SomeClass<Foo>(); var obj2 = new SomeClass<Bar>(); var obj3 = new SomeClass<Baz>();
Edit: From the comments below
I tested " var obj3 = new SomeClass<Baz>(); " and it works, but I don't understand why. I think I donโt understand this statement: "Secondly, all you have done is declare a type parameter that has the same name as the interface."
When you declare a public class definition of a public class Blah<T> , T is a placeholder. This is a type parameter that will be populated later. In your second version of the public class SomeClass<ISomeInterface> , ISomeInterface is the placeholder name! This is not an interface, it does not limit the class to using ISomeInterface , it just uses the same name as the name of the type parameter. The type argument can be any. This is the argument that the placeholder fills. var foo = new SomeClass<string>() . Here the general parameter was populated with string .
Fill in the argument by doing what I did earlier, just instantiating
var instance = new SomeClass<string>();
Or you can populate it using a generic type as the base type for another type.
class AppleSomeClass : SomeClass<Apple>
The fact is that he agrees to use T in one situation with a type parameter, but this is only an agreement. T can be called anything instead. W. X. Apple. You have found that you can also call it the same as the existing type, which unfortunately has led to your confusion here.
Original answer continued.
With restrictions, you can restrict the type parameter to a class or universal method in order to have specific properties for it. For example, you can restrict it to a reference type or a value type.
where T : class // reference type where T : struct // value type
You can specify that it should be obtained from a class or implement an interface
where T : Foo // derives from Foo where T : IFoo // implements IFoo
And you can require it to have a constructor without parameters
where T : new()
And you can match them in the order above. A class or structure constraint should be the first, followed by the base type or interface, and finally the constructor.
where T : class, IFoo where T : class, new() where T : class, Foo, new()