Generic Constraints10:06 with Jeremy McLain
Sometimes we need to place limits on the types that a generic class or method can accept.
We can call the enumerable compositor class finished at this point, but 0:00 I'd like to demonstrate another feature of generics. 0:04 When writing a generic method or class, it isn't always possible to write it in such 0:07 a way that it can be used with any type of object. 0:12 Sometimes, we want to purposefully limit what the generic type parameter can be 0:15 in order to prevent the class or method from being misused in some way. 0:20 For example, 0:24 let's say we have a method that given two objects will return the lesser of the two. 0:25 We'll call this method,min. 0:31 Let's add it to the tills class 0:33 So we'll say, public static, and 0:42 this will be a generic method that will return the generic type. 0:45 And we'll call it Min, specify the generic parameter here. 0:50 It'll take two objects of type T, so take T item1, and item2. 0:55 Min will compare item1 with item2 and return the smallest, 1:04 but the Min method doesn't know what the type T is. 1:10 It could be a numeric type such as int or double, or it could be some other class. 1:14 Right now, 1:19 users of this method could use any type they wanted as the type parameter. 1:20 We need to make sure that T is some type that can be compared. 1:25 In order to do that, we need to constrain what T can be. 1:30 For example, we could say that T must implement the IComparable interface. 1:34 The IComparable interface can be found in the .NET framework. 1:40 The IComparable interface specifies that the type must have a compared to method. 1:43 To constrain what T can be, 1:49 we just add where T : IComparable of type T. 1:54 The IComparable interface is provided in the System namespace. 2:04 So this is saying that T must implement the IComparable of T interface. 2:09 Now in the body of the method, 2:15 we can use the compare to method to compare two objects. 2:16 So say return item1.CompareToitem2, 2:20 and if that's less than 0 2:27 then we'll return item1. 2:32 If not, we'll return item2. 2:36 So, if ComparedTo returns an item less than 0, 2:41 then it's saying that the object is less than the item passed in. 2:45 Interfaces are just one way to constrain a generic type parameter. 2:51 In the teachers notes, 2:56 you'll find a link to an MSDN page that lists other generic constraints. 2:57 Let's take a look. 3:02 These are all the different types of constraints that can be applied 3:05 to a generic parameter. 3:08 Where T is a struct is essentially saying that T must be a value type. 3:10 Where T is a class is saying that T must be a reference type. 3:15 Where T:new means that T must have a parameter list constructor. 3:20 This one means that T must drive from the specified base class. 3:26 This next one is the one we're familiar with, where T must implement 3:32 the interface, And where T is U Means that if we were to provide both T and 3:36 U as type parameters, then T must derive from U. 3:43 Let's see another example of using generic constraints. 3:50 This time, let's add a method to the numerable compositor class. 3:54 This method will allow converting the collection into 3:59 any type of collection specified by a generic parameter. 4:02 So down here at the end, I'll say public, 4:06 and the type of the collection returned will be specified by a generic parameter. 4:12 But we can't call it T because Ts already used in this class. 4:19 We have to call it something else. 4:24 So I'll call it TCollection, And I'll call the method To. 4:26 Here's where we specify the parameter type. 4:34 And it won't take any method parameters. 4:39 We'll need to constrain the TCollection type parameter. 4:42 So, we'll say where TCollection is and 4:45 ICollection of T. 4:53 And it has a parameter list constructor. 5:00 So we'll say new. 5:04 Now, because we've constrained TCollection to have a parameter list constructor, 5:07 we can call that constructor to instantiate a new instance of it. 5:12 So, I'll say var collection = new TCollection. 5:17 We wouldn't have been able to do this had we not included this constraint. 5:26 Now, we'll loop through every item in the current collection that is 5:33 the enumerable compositor, and add it to the new collection we just created. 5:38 So we'll say foreach(var item in this), 5:43 collection.Add(item). 5:53 Now, we wouldn't be able to call the .Add method on collection, 5:59 had we not included this constraint here. 6:05 Because ICollection specifies that 6:07 anything that implements ICollection must have a method named add that takes T. 6:13 Finally, we return the new collection. 6:19 Now, we can use this method to create a hash set 6:28 out of multiple collections all at once. 6:32 So let's go back to program that CS. 6:34 We'll say HashSet of int and we'll just call it set =, 6:42 and let's just create a hash set of all of these collections, 6:49 or all of the items in the collection. 6:56 So just copy and paste them down there. 7:02 And then call that to method. 7:04 Now here is where we specify what type of collection we wanna put them in? 7:06 In this case, we wanna put them all into a HashSet. 7:11 So say HashSet of int. 7:16 And there we go. 7:21 Now we could specify anything that implements ICollection and 7:23 has a parameter through the list constructor. 7:28 So, this could be a list or 7:32 any other type of collection that we found or made ourselves. 7:35 So, that means we don't have to write specific methods to convert 7:39 enumerable compositor into other collection types. 7:43 We can just use this generic method for it. 7:46 So far, we've only seen generic constraints being used on generic methods. 7:49 But classes have all the same constraints. 7:55 The syntax is the same. 7:58 Say for example, 8:00 that we only wanted to allow reference types in enumerable compositor. 8:01 We could go up here, and 8:06 say where T is class. 8:10 Notice that we get some red squiggly lines up here in the EC method. 8:17 The compiler is saying that we can't use 8:22 T up here to construct an Enumerable compositor, because it doesn't know for 8:24 sure but the type being used by EC is a reference type. 8:29 We need to add the same constraint on the EC method as well. 8:34 So, say where T is class. 8:38 In reality, we probably wouldn't want to constrain the enumerable compositor to 8:43 only be able to contain reference types. 8:48 There are a number of reasons why constraining a generic class to 8:51 only work with reference types could be useful though. 8:55 This isn't one of those times though. 8:58 I'm only showing this example to show how generic type constraints can be used on 9:04 classes. 9:09 There's more information about the various type constraints and 9:10 why they are useful in this MSDN page. 9:13 Most often, I find myself using the interface constraint. 9:16 However, I've used all of these other constraints in the past at least once. 9:20 So, it's good to know that they're available. 9:25 We've discussed some fairly advanced yet 9:28 very useful features of the C# programming language today. 9:30 As with everything, there's always more to learn. 9:34 If you've taken the prerequisites, 9:37 then you'll find that this workshop caps off most of the main features of C#. 9:39 This is a significant milestone. 9:44 So, congratulations! 9:45 I encourage you to use what you've learned in this workshop 9:48 to create your own generic data structures and methods. 9:51 I believe you'll find that the result will be simpler and 9:54 more readable code that looks professional. 9:57 And, you may find yourself reusing the code in future projects. 9:59 Until next time, happy coding. 10:04
You need to sign up for Treehouse in order to download course files.Sign up