1 00:00:04,991 --> 00:00:08,490 Welcome to this workshop about C# extension methods. 2 00:00:08,490 --> 00:00:10,010 I'm Jeremy. 3 00:00:10,010 --> 00:00:11,550 Have you ever been coding along and 4 00:00:11,550 --> 00:00:15,670 thought, I wish this class I'm using had methods for doing X, Y, or Z? 5 00:00:15,670 --> 00:00:21,050 For example, just the other day, I wanted to randomly pick an item from a list. 6 00:00:21,050 --> 00:00:25,710 But neither the Random class nor the List class have methods for doing this. 7 00:00:25,710 --> 00:00:29,690 Both the list and the Random class are provided by the .NET Framework. 8 00:00:29,690 --> 00:00:34,060 So I can't just go and open up their code files and add a method to them. 9 00:00:34,060 --> 00:00:38,770 Fortunately, .NET has provided a way to add methods to any class, 10 00:00:38,770 --> 00:00:41,290 even if we don't have access to the source code. 11 00:00:41,290 --> 00:00:44,960 This is the purpose of C# extension methods. 12 00:00:44,960 --> 00:00:48,800 Let's take a look at the code that I wrote to randomly pick an item from a list. 13 00:00:48,800 --> 00:00:52,570 Here we have a list of the synonyms for best, and 14 00:00:52,570 --> 00:00:58,160 down here I print out, my dog Jojo is the synonym for best dog. 15 00:00:58,160 --> 00:00:59,110 To get the synonym for 16 00:00:59,110 --> 00:01:03,960 best, I call this GetRandomItem method and pass it that list. 17 00:01:03,960 --> 00:01:08,623 I wrote this GetRandomItem method to get a random item from the list. 18 00:01:08,623 --> 00:01:13,025 Here it takes the list and I construct a random object and 19 00:01:13,025 --> 00:01:17,920 I call next on that random object, and what this does is it just gets 20 00:01:17,920 --> 00:01:22,890 a random index from the list and then returns the item at that index. 21 00:01:22,890 --> 00:01:25,034 Now on the surface, this looks pretty good, but 22 00:01:25,034 --> 00:01:27,138 there are a few things we could do to improve it. 23 00:01:27,138 --> 00:01:31,610 For one this GetRandomItem method isn't very reusable. 24 00:01:31,610 --> 00:01:33,440 It's stuck in the program class. 25 00:01:33,440 --> 00:01:36,630 It's likely that there are other places in the code where we 26 00:01:36,630 --> 00:01:39,190 might want to get a random item from a list. 27 00:01:39,190 --> 00:01:42,620 Methods like this are often called helper methods because 28 00:01:42,620 --> 00:01:45,370 they're used to help the class do something minor. 29 00:01:45,370 --> 00:01:48,010 They aren't considered a core part of the class, and 30 00:01:48,010 --> 00:01:51,090 helper methods like these can quickly clutter up a class. 31 00:01:51,090 --> 00:01:55,020 So it's better if we could move this method outside of this class so 32 00:01:55,020 --> 00:01:57,890 that it could be reused by other code. 33 00:01:57,890 --> 00:02:00,770 Also, it would be more readable if we could just 34 00:02:00,770 --> 00:02:09,229 say, SynonymsForBest.RandomItem, 35 00:02:09,229 --> 00:02:11,650 like this. 36 00:02:11,650 --> 00:02:16,030 But the List class doesn't have a method named RandomItem. 37 00:02:16,030 --> 00:02:19,520 This is what C# extension methods can be used for. 38 00:02:19,520 --> 00:02:24,310 We can add methods so that they appear as if they're part of the original class. 39 00:02:24,310 --> 00:02:27,210 Not every language has extension methods, though, and 40 00:02:27,210 --> 00:02:30,300 developers have been coding for a long time without them. 41 00:02:30,300 --> 00:02:33,200 So, let's take a look at how we would solve this problem 42 00:02:33,200 --> 00:02:35,890 without using an extension method first. 43 00:02:35,890 --> 00:02:40,820 One way we could do this is to extend the list class directly using inheritance. 44 00:02:41,870 --> 00:02:44,410 So, let's create a class library. 45 00:02:45,430 --> 00:02:51,684 Just right click on the solution, go to Add > New Project, 46 00:02:51,684 --> 00:02:56,439 select Class Library, and here I'll create 47 00:02:56,439 --> 00:03:01,582 a new class library called Treehouse.Common. 48 00:03:01,582 --> 00:03:06,397 I often create a class library to contain some of the common code that I want to 49 00:03:06,397 --> 00:03:09,060 share between different programs. 50 00:03:09,060 --> 00:03:11,700 That's where we want to put our List class. 51 00:03:11,700 --> 00:03:17,756 Let's delete this file and 52 00:03:17,756 --> 00:03:25,132 then add a new class for our list. 53 00:03:25,132 --> 00:03:30,407 I'm just gonna to call it List, but I'll put it in a different namespace so 54 00:03:30,407 --> 00:03:35,876 that it doesn't conflict with the System.Collections.Generic.List. 55 00:03:35,876 --> 00:03:41,316 So I'll say, Treehouse.Collections.Generic. 56 00:03:44,818 --> 00:03:47,036 The List will need to be public so 57 00:03:47,036 --> 00:03:51,070 that it can be accessed from outside of the class library. 58 00:03:52,160 --> 00:04:00,630 And it will be a subclass of the System.Collections.Generic.List. 59 00:04:04,310 --> 00:04:08,360 We need to specify what type of item we want our list to contain. 60 00:04:10,590 --> 00:04:11,830 So add a type parameter here. 61 00:04:13,190 --> 00:04:17,040 Now if we were doing this properly, we would create constructors for 62 00:04:17,040 --> 00:04:22,330 each of the constructors in the base System.Collections.Generic.List class. 63 00:04:22,330 --> 00:04:23,660 Let's skip that for right now. 64 00:04:24,850 --> 00:04:29,324 Right now, let's copy this GetRandomItem method from 65 00:04:29,324 --> 00:04:34,661 the program class over here and move it over here to the List class. 66 00:04:39,476 --> 00:04:40,708 Let's make it public. 67 00:04:42,826 --> 00:04:44,520 And it's no longer static. 68 00:04:46,060 --> 00:04:48,420 We'll just call it RandomItem. 69 00:04:48,420 --> 00:04:49,980 And instead of returning a string, 70 00:04:49,980 --> 00:04:54,500 we'll have it return the type of the item that's contained in the list. 71 00:04:54,500 --> 00:04:58,894 We don't need to pass it the list and 72 00:04:58,894 --> 00:05:04,020 we'll get the item from the list itself, 73 00:05:04,020 --> 00:05:09,746 just say this, and just change this to Count. 74 00:05:09,746 --> 00:05:14,273 So now we have an instance method on our new List class that will 75 00:05:14,273 --> 00:05:17,520 return a random item from the list. 76 00:05:17,520 --> 00:05:21,590 Something else we could do here so that we're not creating a new random object 77 00:05:21,590 --> 00:05:26,150 every time the random method is called, or the random item method is called, 78 00:05:26,150 --> 00:05:30,370 is we can move this outside of this method and 79 00:05:30,370 --> 00:05:34,490 make it a static field, so just say private static. 80 00:05:38,600 --> 00:05:45,183 Random equals new random, type random. 81 00:05:48,807 --> 00:05:49,430 There we go. 82 00:05:51,480 --> 00:05:54,190 Now if we go back over to the program class, 83 00:05:54,190 --> 00:05:57,410 we still don't have the random item method on our list. 84 00:05:57,410 --> 00:06:01,760 That's because we're still using the System.Collections.Generics 85 00:06:01,760 --> 00:06:03,160 version of the list. 86 00:06:03,160 --> 00:06:04,860 We need to change it to use our new List. 87 00:06:06,010 --> 00:06:10,572 So we'll just change this namespace up here from 88 00:06:10,572 --> 00:06:17,597 System.Collections.Generic to Treehouse.Collections.Generic. 89 00:06:20,011 --> 00:06:21,970 Looks like I probably misspelled. 90 00:06:23,360 --> 00:06:24,580 I see what the problem is. 91 00:06:24,580 --> 00:06:28,710 We need to add a reference to our new class library here. 92 00:06:28,710 --> 00:06:33,623 So say Add Reference > Projects > Treehouse.Common. 93 00:06:35,789 --> 00:06:38,419 There we go, that should fix it. 94 00:06:41,268 --> 00:06:44,318 So now we're using our new type of list, 95 00:06:44,318 --> 00:06:48,490 which is just a subclass of the list provided by .NET. 96 00:06:48,490 --> 00:06:51,260 However, in order to use this new method, 97 00:06:51,260 --> 00:06:56,126 the list had to be of type Treehouse.Collections.Generic.List, 98 00:06:56,126 --> 00:06:59,270 instead of .NET's implementation of the list. 99 00:06:59,270 --> 00:07:03,910 We're no longer using the List class from .NET, but had we gotten this list of 100 00:07:03,910 --> 00:07:08,790 synonyms from some other source or library of code that didn't know about 101 00:07:08,790 --> 00:07:13,510 our new fangled list type, it probably wouldn't be the right type. 102 00:07:13,510 --> 00:07:16,800 Most likely, it would be the List that comes with .NET. 103 00:07:16,800 --> 00:07:21,030 Sometimes it makes sense to make a subclass of List and 104 00:07:21,030 --> 00:07:24,090 create our own list that has a bunch more features in it. 105 00:07:24,090 --> 00:07:28,250 But adding one method isn't enough justification 106 00:07:28,250 --> 00:07:31,500 to warrant creating a whole new type of List. 107 00:07:31,500 --> 00:07:34,130 Instead of creating a new type of List, 108 00:07:34,130 --> 00:07:38,460 we could just create what many refer to as a utility method. 109 00:07:38,460 --> 00:07:42,810 To do that, let's change our List class over here. 110 00:07:42,810 --> 00:07:48,160 Let's actually change it to be called ListUtils. 111 00:07:48,160 --> 00:07:53,621 This is a common way of naming classes that contain utility methods. 112 00:07:53,621 --> 00:07:55,720 We'll also make it a static class. 113 00:08:04,816 --> 00:08:07,380 Let's change our RandomItem method so 114 00:08:07,380 --> 00:08:13,270 that it takes a Type parameter, and we'll also make it static as well. 115 00:08:15,650 --> 00:08:16,170 In order for 116 00:08:16,170 --> 00:08:20,060 it to get an item from the list, it needs to take the list as a parameter. 117 00:08:20,060 --> 00:08:24,417 So we'll say List, 118 00:08:24,417 --> 00:08:28,580 and we just call it list. 119 00:08:29,980 --> 00:08:33,366 So this is starting to look like the method that we originally had 120 00:08:33,366 --> 00:08:34,565 in the program class. 121 00:08:40,454 --> 00:08:47,314 We also need to add the System.Collections.Generic 122 00:08:47,314 --> 00:08:49,856 namespace up here. 123 00:08:51,828 --> 00:08:55,600 Now over in Program.cs, 124 00:08:55,600 --> 00:09:00,402 we'll need to change this back to 125 00:09:00,402 --> 00:09:06,580 System.Collections.Generic as well. 126 00:09:08,148 --> 00:09:12,250 But now we don't have a List class that contains a RandomItem method. 127 00:09:12,250 --> 00:09:13,204 So instead, 128 00:09:13,204 --> 00:09:19,028 what we have to do is call the RandomItem method that's in our ListUtils class. 129 00:09:19,028 --> 00:09:23,265 So it'll be ListUtils.RandomItem, and 130 00:09:23,265 --> 00:09:27,507 we'll pass in the synonymsForBest list. 131 00:09:34,736 --> 00:09:39,168 We still need to have a using statement for 132 00:09:39,168 --> 00:09:43,738 our Treehouse.Collections namespace. 133 00:09:47,394 --> 00:09:48,800 There we go. 134 00:09:48,800 --> 00:09:53,090 While we're at it, let's go ahead in change the name of this file to be 135 00:09:53,090 --> 00:09:57,140 ListDetails as well, to match the class name. 136 00:10:01,190 --> 00:10:05,080 So now we have our reusable RandomItem method. 137 00:10:05,080 --> 00:10:10,250 But it isn't quite as readable or useful as the RandomItem 138 00:10:10,250 --> 00:10:14,140 method that we had when we could just call it right on the List class. 139 00:10:14,140 --> 00:10:16,805 We can get some of this readability back and 140 00:10:16,805 --> 00:10:19,845 ease-of-use by using a C# extension method. 141 00:10:19,845 --> 00:10:27,303 What we want is to be able to call the RandomItem 142 00:10:27,303 --> 00:10:33,439 method right on the list, like this. 143 00:10:33,439 --> 00:10:37,880 To do that, let's take another look at our ListUtils class. 144 00:10:37,880 --> 00:10:42,160 To turn our RandomItem method into an extension method, 145 00:10:42,160 --> 00:10:45,810 all we have to do is add the keyword this here. 146 00:10:48,493 --> 00:10:51,285 Now our red squiggly lines have gone away and 147 00:10:51,285 --> 00:10:55,635 we can call the RandomItem method directly on a list. 148 00:10:55,635 --> 00:10:59,745 So adding the List keyword here right before the type parameter 149 00:10:59,745 --> 00:11:03,225 made this static method into an extension method. 150 00:11:03,225 --> 00:11:07,845 What the List parameter does is it tells C# that 151 00:11:07,845 --> 00:11:12,600 this method can be called on any object of type List. 152 00:11:15,310 --> 00:11:17,700 In order for this to be an extension method, 153 00:11:17,700 --> 00:11:23,670 it must be a public static method inside of a public static class. 154 00:11:23,670 --> 00:11:28,035 So this works just like a utility method, only we don't have to say 155 00:11:28,035 --> 00:11:32,680 ListUtils.RandomItem and then pass in the list. 156 00:11:32,680 --> 00:11:37,490 Instead, we can just call RandomItem right on an object of List. 157 00:11:37,490 --> 00:11:40,510 In fact, we can even make it better than that. 158 00:11:40,510 --> 00:11:45,970 We can change the type that the extension method can be called on to an interface. 159 00:11:47,440 --> 00:11:49,960 So now, the RandomItem method 160 00:11:49,960 --> 00:11:54,920 can be called on any object that implements the IList interface. 161 00:11:54,920 --> 00:11:56,460 That's pretty cool. 162 00:11:56,460 --> 00:12:00,530 To make it clear that this class contains extension methods, 163 00:12:00,530 --> 00:12:02,369 let's rename the name of the class. 164 00:12:03,620 --> 00:12:07,361 Let's name this IListExtensions. 165 00:12:10,402 --> 00:12:12,680 We'll also rename the file. 166 00:12:20,236 --> 00:12:22,536 Let's go back to Program.cs. 167 00:12:25,954 --> 00:12:30,713 Notice what happens when I comment out this using statement for 168 00:12:30,713 --> 00:12:33,710 Treehouse.Collections.Generic. 169 00:12:33,710 --> 00:12:39,320 We lose the ability to call the RandomItem extension method on synonymsForBest. 170 00:12:39,320 --> 00:12:43,130 This is how we provide scope for extension methods. 171 00:12:43,130 --> 00:12:47,800 By saying that we're using the Treehouse.Collections.Generic namespace, 172 00:12:47,800 --> 00:12:50,760 we're also saying that we want to have access to 173 00:12:50,760 --> 00:12:54,600 any extension methods that are declared inside that namespace. 174 00:12:54,600 --> 00:12:57,380 So extension methods are pretty nifty and 175 00:12:57,380 --> 00:13:00,750 they help to keep our code clean, dry, and readable. 176 00:13:00,750 --> 00:13:04,010 Let's take a look at a few more features of extension methods 177 00:13:04,010 --> 00:13:05,020 by writing a few more.