Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

122
Views
Is there a way to detect a C# 10 breaking change in the resolution for extension methods?

Consider the following code:

using System;

static class Program
{
    public static void Main()
    {
        Test test = new Test();
        test.Method(()=>{});
    }
}

public sealed class Test
{
    public void Method(Delegate _)
    {
        Console.WriteLine("Test.Method(Delegate)");
    }
}

public static class TestExt
{
    public static void Method(this Test self, Action _)
    {
        Console.WriteLine("TestExt.Method(Action)");
    }
}

In C# 9.0 targeting net48, this outputs TestExt.Method(Action)

In C# 10.0 targeting net6.0, this outputs Test.Method(Delegate)

Obviously this is a breaking change because the extension method may execute different code.

My question is: Is there a way to detect this sort of breaking change in the code without inspecting all the code? For example, is there a code analysis rule that we can enable to detect this sort of code?

This change has actually caused a genuine bug in our code base.


Note that this difference in behaviour is only occurring because of changes to the extension method resolution. If instead of an extension method, the method is in the Test class itself then both language versions call Test.Method(Action):

static class Program
{
    public static void Main()
    {
        Test test = new Test();
        test.Method(()=>{});
    }
}

public sealed class Test
{
    public void Method(Delegate _)
    {
        Console.WriteLine("Test.Method(Delegate)"); // Not called by either version.
    }

    public void Method(Action _)
    {
        Console.WriteLine("TestExt.Method(Action)"); // Called by C#9 and C#10.
    }
}

Background information:

This breaking change has bitten us because we have (rightly or wrongly) an extension method for Control.BeginInvoke() along these lines (error handling omitted):

public static void BeginInvoke(this Control control, Action action)
{
    if (control.IsHandleCreated)
        tryBeginInvoke(control, action);
}

This is no longer called for code like:

this.BeginInvoke(() => someMenu.Visible = somethingIsAvailable());

Instead, Control.BeginInvoke(Delegate) is called, which omits the check for control.IsHandleCreated and the tryBeginInvoke() error handling method.

over 4 years ago · Santiago Trujillo
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!