54

I've struck upon something I don't really understand.

I have a project, where I have an interface that is internal. The class that implements that interface is also internal. In the implementation of the interface, I make all the members that I implement, internal. I did not do an explicit implementation.

I have two interfaces and two classes that implement those interfaces where this works fine.

It would look something like this:

internal interface IA
{
    void X();
}

and then

internal class CA : IA
{
    internal void X()
    {
        ...
    }
}

This works fine for the two aforementioned classes. But when I try to do it with another interface and class, it doesn't work. In fact, for the example above, I get the error:

'WindowsFormsApplication1.CA' does not implement interface member 'WindowsFormsApplication1.IA.X()'. 'WindowsFormsApplication1.CA.X()' cannot implement an interface member because it is not public.

I realize I can make the methods public or do an explicit implementation (and omit the internal and public modifiers), but I'm simply confused as to why it works with the two classes it works with and yet I seem to be unable to replicate it anywhere else.

Butchering the code a bit (because it's confidential), this is one of the ones that actually works in my project.

internal interface IScanner
{
    void SetHardware(Hardware hardware);
    void Start();
    void PauseScan();
    void ResumeScan();
    void Stop();
    bool InScan { get; }
    event ScanCompleteHandler ScanComplete;
}

Then I have the class:

internal class MyScanner : IScanner
{
    internal void SetHardware(Hardware hardware)
    {
       ...
    }

    internal void Start()
    {
        ...
    }

    internal void Stop()
    {
        ...
    }

    internal void PauseScan()
    {
        ...
    }

    internal void ResumeScan()
    {
        ...
    }

    internal bool InScan
    {
        get
        {
            ...
        }
    }

    internal event ScanCompleteHandler ScanComplete;
}

To make things even stranger, I created another internal class called Temp. I then had it implement the IScanner interface and I copied and pasted the implementation from MyScanner over to it and it won't compile, giving me the error that: "cannot implement an interface member because it is not public."

Can anyone explain this inconsistency?

Thanks

(Updated to fix a typo and clarify some text)

EDIT: Additional Information

I ran the code through reflector and my implementations have been compiled as explicit implementations, even though they aren't explicit. Reflector shows no signs of the internal keywords. All I can guess is that this is some sort of glitch in the compiler that, for some reason, allowed me to make them internal and implicit and that it somehow resolved that as being an explicit implementation.

I've looked over the code a number of times. I can't find any other explanation for it.

River
  • 8,585
  • 14
  • 54
  • 67
Pete
  • 6,585
  • 5
  • 43
  • 69
  • Is your MyScanner class in the same assembly as IScanner? – Rohan West May 24 '11 at 21:56
  • 1
    Yes, all the code is in a single assembly. Also, that last line of the last code example should be: internal event ScanCompleteHandler ScanComplete; I've edited the real code a bit, but there's no inconsistency between the interface and implementation in the actual code. I just made an error in editing for the example. – Pete May 24 '11 at 22:02
  • Which version of the C# compiler are you using? The example you gave with `internal interface IA` and `internal class CA : IA` does not compile with C# 4.0. – Steve Guidi May 25 '11 at 00:04
  • I'm using 4.0. And yes, that example doesn't compile, but the other example does in one place in my code, but not another. There appears to be confusion about my actual question. My question is not how should I do this. My question is: Why is the compiler allowing it sometimes and not others. – Pete May 25 '11 at 04:59
  • I continue to get upvotes on this and obviously a lot of people have read it (this is nearly 2 1/2 years after the original post). I'm curious if others have run into this behavior or if it's merely of interest to people. – Pete Dec 27 '13 at 19:24

6 Answers6

26

If you are implicitly implementing an interface I believe that the member must be declared public. In your example, CA attempts to implicitly implement the X() method but isn't declared public. If you want to keep X() as internal then you should use explicit interface implementation.

void IA.X() { /* stuff */ }

However, I'll also add that making the X() method public wouldn't do any harm anyway as the class is internal so that member is already restricted by that access modifier... That is, it's already effectively internal... So you might as well just make it public!

svick
  • 236,525
  • 50
  • 385
  • 514
Reddog
  • 15,219
  • 3
  • 51
  • 63
  • 2
    My question isn't how to do it. I understand how it should be done. My question is about the inconsistency and why the compiler is allowing me to implicitly implement the interface members as internal for these two classes, when it apparently shouldn't. – Pete May 24 '11 at 23:45
  • 1
    In your question I thought you said the compiler **wasn't** letting you implement it internally - you even gave the compile error stating as much saying it "cannot implement an interface member because it is not public". – Reddog May 25 '11 at 00:03
  • 4
    I said it was letting me do it for two classes implementing two interfaces, but not for any others. That is, it's allowing it in two places, but not allowing it otherwise. My question was, why the inconsistency? – Pete May 25 '11 at 04:57
  • 2
    having an "internal myclass" with a "public mymethod" throws me off. but it works. go figure. – granadaCoder Nov 25 '15 at 15:32
19

I know it has been a while since this question was asked, but maybe I can shed some light on it. According to the C# language specification found here the behavior you described should not be possible. Because under 20.4.2 Interface mapping it is said that the implementation is either explicit or mapped to a public non-static member. So either you have some other scenario than the one you are describing here, or you found a bug in your compiler :).

S. Larws
  • 363
  • 2
  • 8
3

If your intention is to hide a certain implementation from outside, you can implement it explicitly like this:

internal class LDialogService : ILDialogService, ILDialogInternalService
{

    public async Task<TValue> ShowAsync<TValue>(ILDialogFragment fragment)
    {
        throw new NotImplementedException();
    }

    void ILDialogInternalService.SetComponent(LDialog component)
    {
        throw new NotImplementedException();
    }
}

In the above code, I want to expose ShowAsync method to the outside but keep SetComponent inside. Since ILDialogInternalService is internal, no one can call it from outside except through Reflection.

Luke Vo
  • 17,859
  • 21
  • 105
  • 181
3

Probably that your "Temp" class is public and IScanner is internal. This is the reason why you get this error. I consider this very annoying since your are forced to implement it explicitly you cannot specify them as abstract or virtual. For the virtual stuff, I was forced to do an implicit internal virtual implementation of the same API and then call the implicit version from the explicit one. Ugly.

2

It's OK to have an internal modifier in an Interface declaration however you CAN'T have ANY modifiers INSIDE the interface, in other words, you can't have any modifier for the interface Members. It's simple as that!

Example:

internal interface IA
{
    void X(); //OK. It will work
}


internal class CA : IA
{
    **internal** void X() // internal modifier is NOT allowed on any Interface members. It doesn't compile. If it works in your project it's because either you DON'T have the void X() method in the Interface or your are inheriting from a wrong interface maybe accidentally 
    {
        ...
    }
}

An interface declaration may declare zero or more members. The members of an interface must be methods, properties, events, or indexers. An interface cannot contain constants, fields, operators, instance constructors, destructors, or types, nor can an interface contain static members of any kind. All interface members implicitly have public access. It is a compile-time error for interface member declarations to include any modifiers. In particular, interfaces members cannot be declared with the modifiers abstract, public, protected, internal, private, virtual, override, or static.

Reference: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/interfaces

Rick
  • 138
  • 3
2

To all my knowledge you cannot implement interface methods internal. As you stated you can implement them explicitly but then someone can still do ((IScanner)myScanner).SetHardware(hw)

Are you 100% sure your MyScanner implementation does not do something like this:

internal class MyScanner : IScanner
{
    void IScanner.SetHardware(Hardware hardware) { this.SetHardware(hardware); }
    internal void SetHardware(Hardware hardware)
    {
      ...
    }
    ....
}

or this:

internal partial class MyScanner : IScanner
{
    internal void SetHardware(Hardware hardware)
    {
        ...
    }
}

internal partial class MyScanner
{
    void IScanner.SetHardware(Hardware hardware)
    {
        this.SetHardware(hardware);
    }
}
ChrisWue
  • 18,612
  • 4
  • 58
  • 83
  • 1
    I'm absolutely sure it does not do either of the things you've shown. There is no second explicit implementation and there are no partial classes involved. I agree, to my knowledge, what I've done should not be possible, based on the research I've done since, and yet the code is there and it compiles and executes as I would expect. I just got the bright idea to look at the code in reflector, however, and it appears that the compiled code has an explicit implementation, even though the actual code is not explicit. Interesting... – Pete May 24 '11 at 22:54