Search code examples
c#interfaceimplicit-conversion

implicit internal interface implementation


When I have a public interface

public interface IPub { string Foo { get; set; } }

then I can implement this interface either by doing it explicitly:

public class CFoo : IPub { string IPub.Foo { get; set; } }

or implicitly by using the public modifier:

public class CFoo : IPub { public string Foo { get; set; } }

. Makes sense: The modifier must be public because the interface is public.

But when I have an internal interface

internal interface IInt { string Bar { get; set; } }

then I can only implement it explicitly:

public class CBar : IInt { string IInt.Bar { get; set; } }

or implicitly with the public modifier:

public class CBar : IInt { public string Bar { get; set; } }

, but NOT with the internal modifier:

public class CBar : IInt { internal string Bar { get; set; } }
// compiler error:
//     'CBar' does not implement interface member 'IInt.Bar'.
//     'CBar.Bar' cannot implement an interface member
//      because it is not public.

This make no sense. Why do I need a public modifier when the interface is only internal? Are there any technical reasons why public must always be used in implicit interface implementations, or could the C# developers have made it differently (without needing to change a lot of things in the language)?


Solution

  • The modifier must be public because the interface is public.

    While that would have been a way of determining it: that isn't what the compiler wants. For implicit interface implementation (regardless of the visibility of the interface type), a member must be declared as public, no "ifs", "buts" or "maybes" (the implementing type, however, can be any visibility level)

    Absolutely the language designers could have looked at more complex rules, but: since there is also an option for explicit interface implementation, they presumably didn't feel that it was necessary to do so.


    Specifically, this is §18.6.5 ("Interface mapping") in the specification (v5) - emphasis mine ("I"=interface type, "M"=member, "S"=implementing type):

    • If S contains a declaration of an explicit interface member implementation that matches I and M, then this member is the implementation of I.M.
    • Otherwise, if S contains a declaration of a non-static public member that matches M, then this member is the implementation of I.M. If more than one member matches, it is unspecified which member is the implementation of I.M. This situation can only occur if S is a constructed type where the two members as declared in the generic type have different signatures, but the type arguments make their signatures identical.