Functional Programming8:03 with Jeremy McLain
Extension methods make it easy to add functional methods to any type.
Follow these guidelines when writing extension methods:
- Only create extension methods that you could realistically see as being part of the original class.
- Because methods can be applied to interfaces, we need to be very careful that we’re sticking to the interface, and not creating methods that only make sense for some implementations of the interface.
- Only write extension methods for reusable code. Assume the extension will be reused by others and code it accordingly.
- Extension methods should have a very specific and straight-forward purpose.
- Their implementation should be obvious from the way they are named. They should also be well documented.
- They should be in a limited namespace. This makes it more obvious to coders when they’re using an extension method and it makes it easier to scope methods to files. Don't forget about "using static".
- Extension methods are highly reusable and you never know how they’ll be used. So they need to be tested thoroughly.
The situation I use extension methods the most in is with delegates and 0:00 lambda functions. 0:04 This is also known as functional programming. 0:06 Instead of calling methods and passing in parameters, 0:09 with functional programming we apply simple functions to data. 0:12 Many people agree that the resulting code is both more succinct and readable. 0:16 In fact, most Linq methods take a function delegate as one of their parameters. 0:20 Most of the Linq methods we know and love are defined in System.Linq.Enumerable. 0:26 Let's take a look. 0:31 Here's the Enumerable class in System.Linq. 0:33 If you go through these methods, 0:35 you'll notice that these are all extension methods. 0:37 Notice how many of them take, 0:41 as one of their parameters, an action or func delegate. 0:42 Some of the Linq methods I find myself using a lot 0:46 are these ones that start with the word First. 0:49 These methods search the collection for the first matching item. 0:52 If no item is found, then an invalid operation exception is thrown. 0:57 Or in the case of the FirstOrDefault methods, the default value for 1:01 the type of item in the collection is returned. 1:05 Let's write our own method that, instead of throwing an exception or 1:07 returning the default value, will return whatever it's told to return. 1:12 Almost all Linq methods extend IEnumerable. 1:17 So we'll say public static, and 1:20 the thing it will return will be of type T, or the parameter we tell it to. 1:23 We'll just call it FirstOr, set the parameter type, 1:28 say this IEnumerable<T>. 1:36 Now this first parameter will be of type Func, which is a delegate type. 1:43 It will take a T and return a bool, and we'll name it predicate. 1:50 So this function will be called on each item in the IEnumerable 1:57 to determine if it's found the item it's looking for. 2:01 If it doesn't find the item it's looking for 2:04 in the IEnumerable, we need to tell it what to do. 2:06 So we'll pass in another function, so say Func, 2:10 and it'll just return an item of type T. 2:14 And I'll call it onOr. 2:18 We need to check to make sure that this isn't null. 2:24 We can actually just copy that code from StringExtensions. 2:27 So here's null check, and we throw ArgumentNullException if this is null. 2:42 To check to see if the item we're looking for is in IEnumerable, 2:47 we'll just call the FirstOrDefault method from Linq. 2:51 So say T found = @this.FirstOrDefault, 2:55 and pass in the predicate. 3:02 If(found.Equals) the default value for T. 3:13 So to get the default value for T, there's a special operator in C# called default. 3:19 Say default, and we just pass in the type. 3:25 So this will return the default value for T. 3:29 So if T was int, it would return 0. 3:34 If it was a float, it would return 0.0. 3:38 If it was any other type of class, it would return null. 3:41 If it was a C# struct, it would return the default value for that struct. 3:46 So if found equals the default value for t, 3:52 that means FirstOrDefault couldn't find the item using the predicate. 3:54 In that case, we'll call our onOr function that was passed in. 3:59 It will return an object of type T and 4:03 we'll just return that, so say found = onOr(). 4:08 Finally, we'll return found. 4:14 Let's go back to Program.cs and use our FirstOr method. 4:18 We can get rid of these lines here. 4:24 Let's say var best = synonymsForBest.FirstOr(), 4:34 and we'll for the first thing in synonymsForBest that 4:39 has a length that is an even number of characters. 4:44 So say s, s.Length.IsEven, and 4:49 here we'll need to pass in what we want our 4:53 FirstOrMethod to return if it can't find any 4:58 words in the list that have an even length. 5:03 For that, let's use our RandomItem method. 5:09 So we'll just say synonymsForBest.RandomItem, 5:12 and we'll change this to just return best. 5:17 You might be wondering why the third parameter to our FirstOr method 5:23 is a function and not just a parameter of type T. 5:28 After all, we could have just called RandomItem and 5:33 gotten the item, and then just passed that in here as the parameter. 5:38 The reason is, 5:43 we don't want the RandomItem method to be called unless it needs to be. 5:44 If FirstOr finds an item in the list that has an even length, 5:50 then it should just return that. 5:56 If it can't find one, then only then should it call our RandomItem method. 5:58 This is known as lazy evaluation. 6:04 Our RandomItem method won't be called unless it absolutely needs to be. 6:06 This is one of the great things about functional programming, and 6:11 C# extension methods allow us to add functional methods to any type of object. 6:14 >> As you can see, extension methods can be a big asset when programming in C#. 6:20 However because they make code more readable, 6:25 there's a tendency to make extension methods for everything. 6:28 They can actually cause confusion and 6:32 end up making code less readable if they're over used like that. 6:34 Here are some guidelines when considering whether or 6:38 not to write an extension method. 6:40 Only create extension methods that you could realistically see 6:43 as being part of the original class. 6:47 Because methods can be applied to interfaces, 6:49 we need to be very careful that we're sticking to the interface and 6:52 not creating methods that only make sense for some implementations of the interface. 6:55 Only write extension methods for reusable code. 7:00 Assume that the extension will be reused by others, and code it accordingly. 7:03 Extension methods should have a very specific and straightforward purpose. 7:08 This is true for most methods, but even more so for extension methods. 7:12 Their implementation should be obvious from the way they're named. 7:17 They should also be well documented. 7:20 They should be in a limited namespace. 7:23 This makes it more obvious for coders when they're using an extension method, and 7:26 it makes it possible to scope methods to specific files. 7:30 Extension methods are highly reusable and 7:34 you never know how they'll be used, so they need to be tested thoroughly. 7:37 Luckily, extension methods lend themselves to be tested 7:42 since they're public static methods. 7:45 Extension methods are just one more tool to 7:48 have in your toolbox as a software developer. 7:50 I think they're pretty nifty, and 7:53 they're one of the things that make C# such a unique language. 7:54 I hope you have fun making your own extension methods. 7:58 Until next time, happy coding. 8:01
You need to sign up for Treehouse in order to download course files.Sign up