Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual Studio 2015 extension method call as method group

I have an extension method like

public static void RemoveDetail<TMaster, TChild>(this TMaster master, TChild child)
        where TMaster : class, IMaster<TChild>
        where TChild : class, IDetail<TMaster>;

And I have two classes

public class Principal : IMaster<Permission>
{
        public virtual IEnumerable<Permission> Permissions { get; }
}

and

public class Permission : IDetail<Principal>

I call RemoveDetail from an Action accepted by method public static void Foreach<T>(this IEnumerable<T> source, Action<T> action);:

aPrincipal.Permissions.Foreach(x => aPrincipal.RemoveDetail(x));

ReSharper suggest me to replace this call with method group like

aPrincipal.Permissions.Foreach(aPrincipal.RemoveDetail);

This worked fine in VS2013 and previous but it fails on compilation in VS2015 with

'Principal' does not contain a definition for 'RemoveDetail' and no extension method 'RemoveDetail' accepting a first argument of type 'Principal' could be found (are you missing a using directive or an assembly reference?)

Anyone has a suggestion? Do I have to update all of the usages and make ReSharper to avoid this replacement?

like image 235
dvas_dubna Avatar asked Sep 02 '15 10:09

dvas_dubna


2 Answers

I was able to reproduce your problem

public interface IDetail<T>
{

}

public interface IMaster<T>
{

}

public class MyClass
{
    public void method()
    {
        Principal aPrincipal = new Principal();
        aPrincipal.Permissions.Foreach(x => aPrincipal.RemoveDetail(x)); // No suggestion from resharper
    }
}

public class Permission : IDetail<Principal>
{

}

public class Principal : IMaster<Permission>
{
    public virtual IEnumerable<Permission> Permissions { get; }
}

public static class Class
{
    public static void RemoveDetail<TMaster, TChild>(this TMaster master, TChild child)
        where TMaster : class, IMaster<TChild>
        where TChild : class, IDetail<TMaster>
    {

    }

    public static void Foreach<T>(this IEnumerable<T> source, Action<T> action)
    {

    }
}

The resharper does not suggest anything. so probably you have to update your Resharper to newer version. probably was a bug which is fixed now.

If this is not like the way you do. then you have to put more information.

Also Compiler gives same error when i try to convert it to method group. So this question may remain: Why Compiler cant do this?

Edit:

To fix this problem you have to call the RemoveDetail method from inside Principal. so make your Principal class like this.

public class Principal : IMaster<Permission>
{
    public virtual IEnumerable<Permission> Permissions { get; }

    public void RemoveDetail(Permission p)
    {
        Class.RemoveDetail(this, p);
    }
}

I think there is kind of ambiguous inside compiler (Possibly bug) that cant recognize RemoveDetail method. how ever compiler tries to find it inside Principal. so you can fix it with creating RemoveDetail inside Principal and call a static RemoveDetail from there.

Edit 2:

The problem is generic type constraint.

where TMaster : class, IMaster<TChild>

This makes compiler to look at class which implements IMaster<TChild> and thats Principal. if you remove this where clause it will solve the problem. otherwise the compiler expects that it should be Principal.

If you use lambda you remove this ambiguity.

aPrincipal.RemoveDetail // compiler expects property/field/method in Principal
                        // but compiler forgets method group and static generic method!
x => aPrincipal.RemoveDetail(x) // this is no more like property or field
                                //but a method that is considered static generic method!

So thats a C#6 bug

like image 174
M.kazem Akhgary Avatar answered Sep 19 '22 13:09

M.kazem Akhgary


I gave a feedback on this subject to Microsoft on September the 3rd 2015 here:
https://connect.microsoft.com/VisualStudio/feedback/details/1747835/visual-studio-2015-extension-method-call-as-method-group

Today I got this feedback from Neal [MSFT]:

This is fixed in VS2015 Update 1.
It is tracked here: https://github.com/dotnet/roslyn/issues/4970

like image 26
Olivier Jacot-Descombes Avatar answered Sep 20 '22 13:09

Olivier Jacot-Descombes