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