Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# extension method overloading causes "missing assembly reference" error

There is a corresponding VS dev ticket https://connect.microsoft.com/VisualStudio/feedback/details/817276/error-cs0012-the-type-is-defined-in-an-assembly-that-is-not-referenced-issued-for-an-extension-method-that-is-not-used

I have 2 extension methods:

public static class ExtensionMethods
{
    public static string GetClientIpAddress(this HttpRequestBase request)
    {
        // ...
    }

    public static string GetClientIpAddress(this HttpRequestMessage request)
    {
        // ...
    }
}

Class HttpRequestMessage is located in System.Net.Http assembly and HttpRequestBase is in System.Web (i.e. in different assemblies). The class ExtensionMethods is located in lets say ProjectA.

This project compiles well and has no issues.

Then I use the first method GetClientIpAddress(this HttpRequestBase request) from another project (lets say ProjectB), like this:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    base.OnActionExecuting(filterContext);
    var sessionContext = DependencyResolver.Current.GetService<ISessionContext>();

    // Call to GetClientIpAddress
    sessionContext.ClientIpAddress =
        filterContext.HttpContext.Request.GetClientIpAddress();
}

The ProjectB already has a reference to System.Web, but when I try to compile it, it causes an compiler error:

The type 'System.Net.Http.HttpRequestMessage' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

What I dont understand is why should I add a reference to System.Net.Http.

It seems that the compiler tries to use the second method GetClientIpAddress(this HttpRequestMessage request) and this causes a missing reference to the assembly. Is this a bug?

When I rename the first method (i.e. get rid of overloads) everything compiles well.

like image 591
neleus Avatar asked Mar 24 '23 05:03

neleus


1 Answers

From C# 5.0 spec, section 7.5.3:

Given the set of applicable candidate function members, the best function member in that set is located. If the set contains only one function member, then that function member is the best function member. Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in §7.5.3.2.

Section 7.5.3.2:

Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN }, MP is defined to be a better function member than MQ if

• for each argument, the implicit conversion from EX to QX is not better than the implicit conversion from EX to PX, and

• for at least one argument, the conversion from EX to PX is better than the conversion from EX to QX.

There's no rule "if the argument type exactly matches the parameter type, pick that one" - so the compiler needs complete type information about all parameter types in order to be able to assess the above rules.

In order to resolve the issue without having to add a reference to System.Net.Http? You've already found the answer - use different method names. That let's you succeed because of the previously quoted part of 7.5.3:

If the set contains only one function member, then that function member is the best function member

like image 104
Damien_The_Unbeliever Avatar answered Apr 25 '23 13:04

Damien_The_Unbeliever