Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload resolution does not look for more specific matches among the members of explicitly implemented interfaces #4871

Open
mklement0 opened this issue Oct 2, 2019 · 4 comments

Comments

@mklement0
Copy link
Contributor

commented Oct 2, 2019

This is a behavior that few people will bump into, but perhaps it should be documented somewhere (the closest candidate topic would be about_Methods):

The scenario is as follows:

  • A given type has a direct member whose parameter is object-typed.

  • The same type also has an explicit interface implementation that has a member of the same name, but with a more specifically typed parameter, say, int.

In this scenario, PowerShell only ever uses the direct-member object-typed overload and never even consults potentially more specific matches among the members of explicitly implemented interfaces.

The workaround is to explicitly cast to the interface in question first.

See also: PowerShell/PowerShell#10654

A quick demonstration:

Add-Type -TypeDefinition @'

   // Interface
   public interface IFoo {
     string Bar(int p);
   }

   // Type that implements the interface
   public class Foo : IFoo {

    // Direct member method named 'Bar'
     public string Bar(object p) { return $"object: {p}"; }

     // *Explicit* implementation of IFoo's 'Bar' method().
     string IFoo.Bar(int p) {
       return $"int: {p}";
     }

    }
'@

[Foo]::new().Bar(1)  # -> 'object: 1'
# !! That is, the less specific `object` overload was chosen,
# !! because the explicit `IFoo` implementation was never consulted.

'---'

# Workaround:
# Cast to `IFoo`
([IFoo] [Foo]::new()).Bar(1)  # -> 'int: 1' - OK
@sdwheeler

This comment has been minimized.

Copy link
Collaborator

commented Oct 16, 2019

Closing this since the related PowerShell issue is closed.

@mklement0

This comment has been minimized.

Copy link
Contributor Author

commented Oct 16, 2019

@sdwheeler:

This issue was created precisely because the related issue was closed:

  • A decision was made not to change the current behavior.

  • Since the current behavior constitutes a pitfall - if an obscure one - it is worth documenting.

@SteveL-MSFT

This comment has been minimized.

Copy link
Contributor

commented Oct 17, 2019

about_Methods is probably ok to document this. @sdwheeler what we should document is that when calling .NET methods, if a method takes an object but has an overload via an interface taking a more specific type, the default method to be called is the one that accepts the object unless you explicitly cast it to that interface. I think an example is sufficient.

@sdwheeler sdwheeler reopened this Oct 17, 2019
@sdwheeler sdwheeler self-assigned this Oct 17, 2019
@mklement0

This comment has been minimized.

Copy link
Contributor Author

commented Oct 17, 2019

I appreciate the clarification, @SteveL-MSFT and thanks for reopening, @sdwheeler.

Just to reiterate one subtlety about the behavior (hopefully the OP makes it clear enough): the problem only occurs if the more specific member is part of an explicitly implemented interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.