c# – Using Extension Methods Safely

Question:

As I understand it, the methods of the class itself take precedence over extension methods.

A natural question arises:

And what will happen if I have spawned extension methods, and then after a while a new version of the library comes out, where the exact same method is defined in the class. It turns out that it will be a priority and may work a little differently – everything will break.

So extension methods are dangerous?

Here's an example:

public class Person
{
    public void Say()
    {
        Console.WriteLine("1");
    }
}

public static class Test
{
    public static void Say(this Person p)
    {
        Console.WriteLine("2");
    }
}

class Program
{         
    static void Main(string[] args)
    {
        var t = new Person();
        t.Say();
    } 
}

Let's say we implemented the Say method as an extension and it outputted 2 us, then an update comes in, and then bam and output 1 . The compiler does not issue any warnings, although it issues a warning if we inherit and declare a method with the same signature and it asks to write new .

It's also funny that you can't control the call to a specific extension method if there are overlaps between the namespaces. In this case, the only option is to call through statics, which kills the usability of extensions.

Answer:

So extension methods are dangerous?

Yes, this is undoubtedly true. Extension methods are a crude hack that violates the principles of object-oriented programming, and in addition to the problem of uncontrolled hiding by members of an extensible class, they also suffer from the problem of conflicts between themselves (after all, different libraries can create extension methods for the same class). They should not be overused.

The Framework Design Guidelines explicitly discourage this:

AVOID frivolously defining extension methods, especially on types you don't own.

It also mentions two cases when the use of extension methods is justified:

  • Adding some functionality to all types that implement a specific interface. In this case, the danger is somewhat lower, because new methods are usually not added to interfaces (since this would require rewriting the code of a bunch of classes that already implement this interface). This is how LINQ works.

  • Methods bound to types defined in your own code. Let's say you create an extension method for the String class that takes an argument of the Person type defined in your project. In this case, the described conflict will also not exist, because even if MS adds a new method to the String class, it will definitely not use the class from your code in any way.

Unfortunately, following these recommendations still does not completely solve the problem, as there are conflicts between the extension methods themselves from different libraries. This is the problem faced by the developers of the MoreLinq library.

Of course, Framework Design Guidelines are guidelines for developers of public API libraries, not any code in applications. But this does not change the essence, since you need to strive to make any code reusable. Projects tend to grow, split, and the like; some code that was previously used only in one project will later want to be transferred to a shared library. Therefore, these recommendations can be largely extended to application code.


Update. C # 8.0 introduces a new feature – default interface methods . Thanks to it, libraries can add new methods to the interface without breaking backward compatibility. Therefore, for interface extension methods, there is now also the problem of potential hiding by the extensible interface method.

On the other hand, this innovation reduces the need to write extension methods to add functionality to interfaces, since this functionality can now be implemented as default methods.

Scroll to Top