84

Ok, so this may be a bit of a silly question, and there's certainly the obvious answer, but I was curious if I've missed any subtleties here.

Is there any difference in terms of visibility/usability between a public member declared in an internal class and an internal member declared in an internal class?

i.e. between

internal class Foo
{
    public void Bar()
    {
    }
}

and

internal class Foo
{
    internal void Bar()
    {
    }
}

If you declared the method as public and also virtual, and then overrode it in a derived class that is public, the reason for using this modifier is clear. However, is this the only situation... am I missing something else?

Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 4
    _If you declared the method as public and also virtual, and then overrode it in a derived class that is public_ **meeeep!**: You are not allowed to increase visibility, only the other way round: You can create a derived class of a public class which is internal (or even nested and private) – springy76 Jun 26 '12 at 15:48
  • 5
    Googlers take note: This near-duplicate [question](http://stackoverflow.com/questions/9302236/why-use-a-public-method-in-an-internal-class/9302642#9302642) contains another particularly excellent answer. – Michael Richardson Aug 04 '14 at 18:02

5 Answers5

68

Consider this case:

public interface IBar { void Bar(); }
internal class C : IBar
{
    public void Bar() { }
}

Here C.Bar cannot be marked as internal; doing so is an error because C.Bar can be accessed by a caller of D.GetBar():

public class D
{
    public static IBar GetBar() { return new C(); } 
}

A commenter asked a follow-up question: is an explicit implementation of an interface method considered to be public, or private? (C# does not allow you to put an access modifier on an explicit implementation.)

Take a step back and think about what exactly is "public" or "private" about a member: people think wrong things like "private means that a method cannot be called from outside the class", but that's not true; the class could make a delegate to a private method, pass it to anyone, and they can then call a private method.

Rather, accessibility determines where the name of a thing can be used! Explicit interface implementations do not add a name to the class declaration space in the first place; they can only be referred to by name via the interface, not the class. It really doesn't make sense to think of explicit interface implementations as public or private because they don't have a name you can refer to.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Thanks Eric, this is another good case. So effectively interface implementation and class inheritance are the reasons for allowing either the `public` or `internal` modifier in an `internal` class. In other cases, they are equivalent it would seem. – Noldorin Apr 02 '10 at 11:11
  • 9
    Eric also answers an almost identical question at: http://stackoverflow.com/a/9302642/398015 There are additional details in his post that add considerable substance to the answer above. – Chris Dec 27 '12 at 15:54
52

A public member is still just internal when in an internal class.

From MSDN:

The accessibility of a member can never be greater than the accessibility of its containing type. For example, a public method declared in an internal type has only internal accessibility

Think of it this way, I would access a public property on....? A class I can't see? :)

Eric's answer is very important in this case, if it's exposed via an interface and not directly it does make a difference, just depends if you're in that situation with the member you're dealing with.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • Yes, this was indeed exactly my thought except for in the case Eric pointed out (as well as the one in my original question). – Noldorin Apr 02 '10 at 11:12
  • It also makes a difference when you use reflection. Default parameter-less methods like Type.GetMethods() only return public members. And the public method inside the internal class still knows that it is public. – springy76 Jun 26 '12 at 15:54
  • 2
    "The accessibility of a member can never be greater than the accessibility of its containing type." While that holds true for some cases, a `public` member of a `private` class is clearly a wider scope than a `private` member of a `private` class (The former being project wide, the latter being class only). – Deanna May 15 '14 at 11:47
  • @Deanna yes...but that doesn't make the former statement false, you're comparing peers not containers with that - where things are accessible doesn't change, since you can't access a public member from outside it's private class container. – Nick Craver May 15 '14 at 15:32
  • So, if I define my class as "internal," do I change my members to "internal" as well? Or should I just let them be public? – paraJdox1 Mar 14 '22 at 06:34
3

Just faced with another example where there is difference between those two, when used from XAML in WPF.

XAML:

<Button Tag="{x:Static vm:Foo+Bar.e1}" />

Code with internal enum compiles successfully:

internal class Foo
{
    internal enum Bar
    {
        e1,
        e2,
    }
}

But surprisingly changing it to public results in error:

internal class Foo
{
    public enum Bar
    {
        e1,
        e2,
    }
}

The last example produces compilation error:

error MC3064: Only public or internal classes can be used within markup. 'Bar' type is not public or internal.

Unfortunately, I can't explain what's wrong with public in this case. My guess is "just because WPF works that way". Just change modifier of the nested class to internal to get rid of error.

nevermind
  • 2,300
  • 1
  • 20
  • 36
2

public members of an internal class can override public members of public base classes and, therefore, be a little more exposed... if indirectly.

1

If it comes to reflection it matters if the member is public or not:

For example you even could pass a nested private class to a WPF binding and the binding would work against the public properties just as usual.

springy76
  • 3,706
  • 2
  • 24
  • 46