More Examples14:05 with Jeremy McLain
Here are some tips on writing extension methods.
As you can imagine extension methods could be misused to cause a lot of confusion. 0:00 Notice how they appear to be part of the original class, but in fact they aren't. 0:05 When writing extension methods, I stick to a set of guidelines. 0:11 We'll go through these at the end of the workshop. 0:15 A good guideline is to only create extension methods that you could 0:17 realistically see as being part of the original class that you're extending. 0:21 A great example of an extension method is the IsEven method called on an integer. 0:25 So let's create a new class. 0:31 We'll call it, IntExtensions. 0:34 Again, we'll make it a public static class. 0:43 And in here, we'll have a public static method that returns a bool. 0:49 And it's called IsEven. 0:56 It's an extension method, so I've to say this and 0:59 the type that it's going to extend is integer. 1:03 I'll just call the parameter, value, here. 1:07 So in our method, we wanna check to see if this value is an even value. 1:12 So we'll return. 1:18 To see if the value is even, we can just divide the value by 2 and 1:20 to see if there's any remainder. 1:24 There's actually a special operator for that in C#, it's called modulus. 1:27 So we can return the value %2. 1:33 And if that is equal to zero then we know that value is even. 1:38 Otherwise it's false. 1:44 Another way to do this is to use a bitwise operator. 1:47 What we can do is we can take the integer value and 1:50 bitwise & it with the value 1, 1:53 because all odd integers have their lowest bit as 1. 1:58 Now don't worry if you're not familiar with bitwise operations. 2:04 This is just a very fast way to determine if the last bit of a integer is 1. 2:08 So now we can call the IsEven method on any integer 2:15 just like it was part of the original class. 2:20 In order to call it though, we need to make sure that we're 2:22 using the Treehouse.Common namespace where we want to use it. 2:25 So up here, we need to add, using Treehouse.Common. 2:29 Now down here, we can say 5.IsEven() and this should return false. 2:37 Now it's conceivable that the Treehouse.common namespace 2:45 has a lot of other classes in it. 2:49 We can reduce the scope even more by using a static using directive. 2:51 So we can actually say using static Treehouse.Common.IntExtensions. 2:56 This works with any static class. 3:04 And this makes it even more obvious that 3:07 we want to use the extension methods in this IntExtensions class. 3:10 Now, instead of using the entire Treehouse.Common namespace and 3:15 pulling in all of the other classes that might be in that namespace, 3:19 we're just pulling in the IntExtensions class. 3:23 And thereby, only pulling in this IsEven extension method. 3:26 Remember that just because there's an extension method that extends a type, 3:30 doesn't mean that it can be used from anywhere the type is used. 3:35 Extension methods are scoped to the namespace that they're declared in. 3:38 And we can further reduce that scope with the using static directive just like this. 3:42 It's a good practice to declare extension methods in a limited namespace. 3:48 For example, 3:53 we could have put the IntExtension class in the system namespace. 3:54 But then this extension method would be available everywhere. 3:58 And it wouldn't be very obvious that this method isn't part of the original 4:02 integer type. 4:05 There are a number of classes and 4:07 interfaces that I find myself writing extension methods for a lot. 4:08 One of those is the string class. 4:13 Let's take a look at the documentation for the string class. 4:15 Here's the documentation for the string class. 4:20 If we find the methods that start with split. 4:22 Here we see the all of the methods that start with split take a character array. 4:26 Now this first one, 4:32 actually takes a character array that's actually a params argument. 4:34 And a params argument allows us to pass in zero, one or 4:38 as many characters as we want and what it does is it just 4:43 combines all those into a single argument of type character array. 4:47 But the thing is, with params arguments, 4:52 is they have to be the last argument in the method. 4:54 So, like this one right here, takes a character array and the second 4:59 argument is the count which is the maximum number of substrings it should return. 5:05 So the first argument here, actually, it's just this regular old character array. 5:11 It's not a params, 5:17 which means we have to instantiate a character array and pass that in. 5:18 So this makes it kind of cumbersome when calling split, 5:24 if we only wanna pass in a single character as the separator. 5:29 We don't wanna have to create a character array every time we call the split method. 5:33 So we can leave this pain a little bit by creating an extension method 5:38 that does this for us. 5:42 So let's go back to our code here and I'll create a new file. 5:44 And it's a string extension, so 5:57 we'll put it in the StringExtensions class. 6:00 So it'll have to be a public static class. 6:08 And we'll make a public static method that returns a string array and 6:15 we'll call it split to match the other ones and it will extend a string. 6:20 So, we'll say this string. 6:26 And here we have to decide what we want to name the this parameter. 6:33 Now there's some debate about what you should name this. 6:36 Personally, I like to call it this. 6:40 But the problem is, is this is a keyword which, 6:43 we can't put it here because it's a keyword in C#. 6:47 It causes the C# compiler to kind of go into a fit. 6:50 So, [LAUGH] well, it just causes a compiler error. 6:56 So what we can do if we want to use a C# keyword as a variable 7:00 is we just prefix it with the @ symbol and this makes a lot of sense because 7:05 this parameter is actually called this parameter. 7:10 [LAUGH] So calling it @this makes a lot of sense. 7:14 Some people don't like that convention and 7:18 it's fine if you don't wanna do it this way. 7:20 Other people like to call the this parameter target or 7:22 source or value or extended or 7:26 something that just makes sense for the method that you code in, at that time. 7:30 I like to call it @this because I don't have to think about what to name the this 7:34 parameter every time I write an extension method. 7:38 It also makes argument null exceptions really obvious and 7:41 I'll show you what I mean in just a little bit. 7:45 Let's continue to write this method. 7:48 So we have to say which character we want to separate the string on, so 7:51 pass in the separator. 7:56 And we also wanna say the maximum number of times we want the string to split, 8:00 so we'll say int count. 8:04 The thing with extension methods is that 8:06 they can actually be called on an object whose value is null. 8:09 Now, if we were to call an instance method. 8:14 A method that's inside of a regular class on null, 8:17 we'd get a NullReferenceException thrown. 8:21 But because split is actually just a regular static method inside of a static 8:24 class and the object that is being called on is just another argument or 8:31 parameter being passed into the method, that means this can actually be null. 8:37 So we have to check for that, and throw an exception if that's the case. 8:42 Just to demonstrate that these extension methods are just really static 8:47 methods inside of a static class, we can go back to the program class and 8:52 change where we're calling random item, 8:57 to actually be look like a normal static method. 9:00 So we can say IListExtensions.RandomItem() and 9:05 we can pass in our list here. 9:11 So now this looks a lot more like the utility function that we had before. 9:15 So back in our split method, we need to check for null. 9:24 So I'll say, if(@this == null), 9:28 Now I've said normally, if a method is called on an object whose value is null 9:35 then we'll get a NullReferenceException. 9:39 But sometimes people actually call extension methods 9:43 like a regular static method. 9:46 So instead of throwing a NullReferenceException which really 9:48 wouldn't make sense if you're calling it as a utility method or as a static method. 9:52 What we'll throw is a ArgumentNullException. 9:56 So I'll say, throw new ArgumentNullException. 10:00 And here, we pass in the name of the argument that is null, 10:06 so in this case it's @this. 10:11 There we go. 10:15 Now there's a cool trick in C#. 10:16 There's an operator called nameof that we can use. 10:18 That can make it so that instead of passing in a string here, 10:24 we can actually just pass in the variable itself and nameof will return 10:29 the actual name, the string, that is the name of the variable. 10:34 This is handy because we may wanna refactor in the future and 10:39 change the name of the variable here. 10:43 And as part of that refactoring, the compiler will catch 10:46 that we've changed the variable and will tell us we also need to change it here. 10:50 Strings can actually be quite dangerous when we're using them to refer to code. 10:54 So it's always best to always just stick in the code. 10:59 Now down here, we can finish implementing our method. 11:03 So, we want to return. 11:05 And we'll just call the regular split method from the string class. 11:08 So we'll say @this.Split(). 11:12 Now, this is how we would normally call this method. 11:16 We would create a new array. 11:20 And in the array, we would specify the separator that we want to split on. 11:25 And then pass in count. 11:35 So there you go. 11:37 So now when we're using this method, instead of calling string.Split, 11:38 creating a new array with the separator we wanna split on, 11:44 we can just call this method like so. 11:48 We'll just say "mySTring".Split('S', 11:51 3) like that. 11:59 Pretty nifty. 12:02 So I mentioned before that calling this parameter @this can 12:09 actually help a little bit when we have argument null exceptions. 12:13 So let's go to program and let's cause one of these exceptions. 12:19 So let's create a string. 12:27 And we'll just call it myString, and set it equal to null. 12:29 And we'll call myString.Split. 12:37 And notice now that there are a lot of different split methods in this 12:45 string class. 12:49 We can go down here, these ones are all part of the regular class. 12:50 And we'll just pass in you can split on a comma, three times. 12:58 And it's not seeing our new extension method because we don't have 13:04 the namespace up here. 13:09 So let's bring this back to using static Treehouse.Common. 13:10 There we go. 13:21 So let's run this and let's see what kind of exception we get. 13:22 All right, so because we're in the debugger, 13:26 it breaks right here where the ArgumentNullException is being thrown. 13:28 And here we see ArgumentNullException was unhandled and 13:33 we go down here, we can click on this view detail. 13:37 And here we see value cannot be null parameter name is this. 13:40 Now my logic for calling the parameter this is because if 13:46 an ArgumentNullException is thrown and the parameter name is this, then I know right 13:51 away that the method that threw this exception is a extension method. 13:55 So that gives me a lot better idea of where to look. 14:01
You need to sign up for Treehouse in order to download course files.Sign up