How to search for YouTube videos in a channel with .NET Core 3
Probably you have already heard of extension methods: those are C# methods used to add new functionalities to an existing class.
This functionality is available since C# 3.0, so it’s largely used and well documented.
The basics of extension method
Let’s say that you have a non-static class that you cannot modify, maybe because it comes from an external library.
1 2 3 |
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token return-type class-name">DateTime</span> BirthDate <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> Surname <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> <span class="token function">GetFullName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token interpolation-string"><span class="token string">$"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">Surname</span><span class="token punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">Name</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
For the Person class we have only the GetFullName
method.
So we can use the Person class this way:
1 |
<span class="token class-name"><span class="token keyword">var</span></span> person <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Name <span class="token operator">=</span> <span class="token string">"Davide"</span><span class="token punctuation">,</span> Surname <span class="token operator">=</span> <span class="token string">"Bellone"</span><span class="token punctuation">,</span> BirthDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1990</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>person<span class="token punctuation">.</span><span class="token function">GetFullName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Nothing difficult, right?
Now we want to get the full name with the birthdate. We have 2 ways to achieve this: using a subclass – terrible idea – or creating an extension method. Let’s go with the second approach!
First of all, we need a static class that contains our method:
1 2 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">MyExtensions</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> |
Now we can create the new method. We must remember 2 things:
- it must be a static method
- the first parameter must be of the same type we want to extend and must be preceded by the
this
keyword
1 2 3 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> <span class="token function">GetFullNameWithBirthDate</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">Person</span> person<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token interpolation-string"><span class="token string">$"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span>BirthDate<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token string">"yyy-MM-dd"</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> - </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span>Surname</span><span class="token punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span>Name</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now we can use it with person.GetFullNameWithBirthDate()
. Easy-peasy.
If you use Visual Studio and you have the Intellisense enabled, you will see those hints, both on the icon and on the description of the method.
Behind the scenes, we are calling the method on the MyExtensions class, not on the person object. Extension methods act just as shortcuts.
1 2 |
person<span class="token punctuation">.</span><span class="token function">GetFullNameWithBirthDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> MyExtensions<span class="token punctuation">.</span><span class="token function">GetFullNameWithBirthDate</span><span class="token punctuation">(</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span> |
Ok, we have seen an overview of this functionality. Let’s go more in details.
Visibility matters
As you may imagine, since extension methods are meant to extend the public behavior of a class, you cannot use a private field (or method) of that class.
So, if we have a private string ID
to our Person class, it won’t be accessible from the extension method.
Of course, you can use both public properties and public methods. In fact, we can do refactor GetFullNameWithBirthDate
to
1 2 3 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> <span class="token function">GetFullNameWithBirthDate</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">Person</span> person<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token interpolation-string"><span class="token string">$"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span>BirthDate<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token string">"yyy-MM-dd"</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> - </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span><span class="token function">GetFullName</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
You can extend subclasses
Say that you have a Student
class that extends Person
:
1 2 |
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Student</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Person</span></span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> StudentId <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Now, among our extension methods, we can add functionalities to Student, and reference the Person class:
1 2 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> <span class="token function">GetFullStudentInfo</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">Student</span> student<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token interpolation-string"><span class="token string">$"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">student<span class="token punctuation">.</span><span class="token function">GetFullName</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string"> - ID: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">student<span class="token punctuation">.</span>StudentId</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Finally, we can create extension methods that will override the ones created for the base class:
1 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> <span class="token function">GetInitials</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">Student</span> student<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token interpolation-string"><span class="token string">$"Student: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">student<span class="token punctuation">.</span>Surname<span class="token punctuation">.</span><span class="token function">ToCharArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span></span><span class="token punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">student<span class="token punctuation">.</span>Name<span class="token punctuation">.</span><span class="token function">ToCharArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span></span><span class="token punctuation">}</span></span><span class="token string">."</span></span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> <span class="token function">GetInitials</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">Person</span> person<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token interpolation-string"><span class="token string">$"Person: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span>Surname<span class="token punctuation">.</span><span class="token function">ToCharArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span></span><span class="token punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">person<span class="token punctuation">.</span>Name<span class="token punctuation">.</span><span class="token function">ToCharArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span></span><span class="token punctuation">}</span></span><span class="token string">."</span></span><span class="token punctuation">;</span> |
So, now
1 2 |
<span class="token class-name"><span class="token keyword">var</span></span> student <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Name <span class="token operator">=</span> <span class="token string">"Elon"</span><span class="token punctuation">,</span> Surname <span class="token operator">=</span> <span class="token string">"Musk"</span><span class="token punctuation">,</span> BirthDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1971</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">,</span> StudentId <span class="token operator">=</span> <span class="token number">123</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>student<span class="token punctuation">.</span><span class="token function">GetFullNameWithBirthDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>student<span class="token punctuation">.</span><span class="token function">GetFullStudentInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>student<span class="token punctuation">.</span><span class="token function">GetInitials</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
will print out
1 2 3 |
1971-06-28 - Musk Elon Musk Elon - ID: 123 Student: M.E. |
A real life example: LINQ
Since C# 3.5 we have a new query language: LINQ.
LINQ stands for Language-Integrated Query, and it is often used when you are working on collections and you need to do some operations on them, like get all the values that match a particular condition or take only the first element of the collection.
An example can be
1 2 |
<span class="token class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> myList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">82</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">223</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">342</span><span class="token punctuation">,</span> <span class="token number">234</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> myList<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
By default, List<T>
does not include a method that returns the first element of the collection. To use it, we need to include LINQ by putting using System.Linq
among the imports.
So yes, we can say that First is a method that extends the List class: LINQ is a set of extension methods!
In fact, we can read its source code and notice this:
1 2 3 |
<span class="token keyword">namespace</span> <span class="token namespace">System<span class="token punctuation">.</span>Linq</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">Enumerable</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">TSource</span> <span class="token generic-method"><span class="token function">First</span><span class="token generic class-name"><span class="token punctuation"><</span>TSource<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">IEnumerable<span class="token punctuation"><</span>TSource<span class="token punctuation">></span></span> source<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">TSource</span> first <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">TryGetFirst</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">bool</span></span> found<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>found<span class="token punctuation">)</span> <span class="token punctuation">{</span> ThrowHelper<span class="token punctuation">.</span><span class="token function">ThrowNoElementsException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> first<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
So, you can extend this library if you want. Let’s say that you need to get a random element from the list; you can create a method like this:
1 2 3 4 5 6 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">T</span> <span class="token generic-method"><span class="token function">GetRandom</span><span class="token generic class-name"><span class="token punctuation"><</span>T<span class="token punctuation">></span></span></span> <span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">IEnumerable<span class="token punctuation"><</span>T<span class="token punctuation">></span></span> source<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>source <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> source<span class="token punctuation">.</span><span class="token function">Count</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ArgumentException</span><span class="token punctuation">(</span><span class="token keyword">nameof</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">Random</span> rd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> source<span class="token punctuation">.</span><span class="token function">ElementAt</span><span class="token punctuation">(</span>rd<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> source<span class="token punctuation">.</span><span class="token function">Count</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
And call it this way:
1 2 |
<span class="token class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> myList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">82</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">223</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">342</span><span class="token punctuation">,</span> <span class="token number">234</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">;</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>myList<span class="token punctuation">.</span><span class="token function">GetRandom</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Wrapping up
Have you ever used extension methods for creating a library?
Anyway, here’s a short recap of the main points:
- all in a static class
- each method must be static
- the extended class must be non-static
- the first parameter must be preceded by the this keyword
- you can use only public fields and methods
- you can extend classes, but also subclasses and structs
- the greatest example of library based on extension methods is LINQ
You can see the full example here.
Source: https://www.code4it.dev/blog/csharp-extension-methods
