17

protected internal:

The union of protected and internal accessibility (this is less restrictive than protected or internal alone)

The CLR has the concept of intersection of protected and internal accessibility, but C# does not support this.

So my question is:

What's the meaning of omitting this Access Modifier, is there a concrete reason? So why C# should not support it?

Omar
  • 16,329
  • 10
  • 48
  • 66
  • 3
    It requires another keyword since it can't be expressed with the existing ones. Any language feature costs a 1000 points, a keyword costs a million points. Too steep. Same in VB.NET btw. – Hans Passant Jan 22 '12 at 21:28
  • @minitech `Protected Friend` is the same as C#'s `protected internal`. It also doesn't allow you to specify the protected-and-internal access that exists in the CLR. – Jon Hanna Jan 23 '12 at 15:08
  • [Related](http://stackoverflow.com/questions/941104/how-to-make-a-property-protected-and-internal-in-c): which asks how to overcome this. – nawfal May 20 '13 at 20:01

7 Answers7

7

Update: C#7.2 is introducing this with the access modifier private protected, which seems wrong in a few ways but does avoid much of the potential for confusion I describe below, so is perhaps the best of a bad bunch.

Personally, I've wanted this quite a few times. There are times when one exposes a class and one or more classes derived from it as public in an assembly, and there are times when some member of the base class is only used by those derived classes and should not be exposed to protected classes in other assemblies (quite often the constructor, so as to prevent other assemblies from having classes that derive from it at all).

It is of course always good to define your access as restrictively as possible, and so the intersection of protected and internal is precisely what is wanted here.

Instead, I've had to kludge it by declaring the member internal. There is now a potential for bugs in my code that wouldn't have been there if I used a language that allowed me to use that intersection.

However, consider the downside.

As it is, there's some confusion about the way that protected internal gives the union of protected and internal. It's probably the most misunderstood access, judged by questions on sites like this.

What should we call it? internal protected? Can you imagine how often people would get that confused with protected internal? We'd want something more clearly differentiated, and we'd want the same for internal protected (because we've still increased its potential for confusion). It's not an impossible problem to answer, but keeping the number of keywords down is a good idea too.

Even if a perfect answer is found to the naming question, the potential for confusion by introducing yet another level of access is not entirely defeated.

So with that in mind, let's look at the upside again. We no longer have to kludge the times we need it by using internal, reducing bugs caused by inappropriately using such a member. Okay, how often does that come up, and how likely would such bugs actually be? Not very often really, and not very likely.

On balance therefore, while I do find myself occassionally wishing C# had this, a moment's pause normally makes me glad they did not.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 2
    You could use them as bitwise flags, sort of, and do something like: `protected & private` -> `private`; `protected | internal` -> `protected internal` -> `protected & internal` -> desired result. – Jesus is Lord Jul 25 '12 at 19:17
6

The intersection of protected and internal would downgrade to a simple internal for code external to your library – meaning it would not accessible, whether from derived classes or otherwise.

As such, the only benefit a protected internal intersection would serve is for disciplining yourself, as the developer of your library, not to access the type/member except from the same or derived classes within your library. It will not make any difference for consumers of your library, since its semantics would be identical to a plain internal.

That said, I would not have found it unreasonable for it to be allowed in C#. Self-discipline often comes in useful; it is the reason why the language designers differentiated between private and internal, despite the two being identical for external consumers.

However, since the distinction between the intersection and the plain internal is small, they probably chose to exclude it in order to mitigate the risk of developers confusing it with the more-useful protected internal union.

Douglas
  • 53,759
  • 13
  • 140
  • 188
  • 1
    No. `protected` means accessible from derived classes, even in other libraries; `internal` means it would not be accessible at all to other libraries. – Douglas Jan 22 '12 at 21:29
  • It’s that way in C# too. I said that the _intersection_ (if it were to exist) would downgrade to an `internal` (or, for that sake, a `private`) for external code. The `protected internal` union is equivalent to a `protected` for external code. – Douglas Jan 22 '12 at 21:38
  • 1
    -1, This whole reply is assuming that there is one developer to the class library and that the class library is small. This is not the case when many people work on an infrastructure together. In that case, the distinction between the intersection and the plain `internal` is quite big. – tsemer Apr 10 '13 at 11:30
3

It was a design decision, but consider what it means:

  • accessible only to derived classes in the same assembly.

This is not a very useful boundary, I can't think of a clear use-case.
And that's why it probably wasn't worth coming up with a new keyword(-combination).

I would rather ask why the CLR supports it. Orthogonality I suppose.

H H
  • 263,252
  • 30
  • 330
  • 514
  • 1
    Then the question turns to why CLR supports it? – Ignacio Soler Garcia Jan 22 '12 at 21:19
  • 2
    +1 I do agree with you. I can't see any real-world usage of this. @SoMoS The CLR supports plenty of things that C# doesn't. – user703016 Jan 22 '12 at 21:20
  • @Somos: exactly. But it supports more features that didn't make it into C#, choices have to be made. – H H Jan 22 '12 at 21:21
  • Why would you do add features to an engine that won't get used at the end? Looks like a waste of time. And it can be useful when a whole company develops a product and several co-workers work on the same assembly. You have to limit them as you do with outsiders. – Ignacio Soler Garcia Jan 22 '12 at 21:24
  • 2
    @Somos: "that won't get used..."- that does not follow here. Other languages might implement it, and I would guess there are examples of usage way down in the BCL. C# is not (the whole) .NET. – H H Jan 22 '12 at 21:26
  • And "several co-workers work on the same assembly" - your main tool would be `private`, with `protected` at some distance. – H H Jan 22 '12 at 21:29
  • 2
    @SoMoS it could be useful if you're just coding on your own, assuming you aren't infallible. Ultimately, it's a feature with pros and cons and a cost to maintain, and when the CLR was designed (and re-designed with later versions) it was decided on balance to included it, and when C# was designed (and re-designed with later versions) it wasn't. All we can really do is examine those pros and cons, rather than arrive at any definitive proof. – Jon Hanna Jan 23 '12 at 15:49
  • If you don't know how this would be useful, you haven't really given it a lot of thought. As a framework developer, I can't count on my hands the number of times in the last 3 years that this has come back to bite me. When you are trying to setup any kind of minimal accessibility internally via interfaces, if you have a class that is restricted to a particular layer (assembly) via being internal, you can't use a protected interface to restrict access to certain functionality to only the classes which have a controlling interest in the nested internal class. – AJ Henderson May 11 '17 at 15:48
2

I wanted to ask this same question, but thankfully SO found this one for me.

I can understand the point of view that it would require either at least a new keyword, or new semantics for existing keywords, so it wasn't supported because the cost-benefit didn't work in its favour.

However, I question whether it's legitimate to avoid implementing this CLR feature because of the narrow use-case or because it could confuse people.

One argument given above is that it's only use would be to enforce self-discipline.

But then the same could be said of any visibility modifier that isn't public. The idea, also, that it would only apply to 'a single developer of a single library' is plainly erroneous, too. Many libraries are developed by teams of people, and it's entirely natural for a developer within that team to add a member that he or she would want to restrict only to internal types derived from his or her base.

Then there's this scenario:

internal class Foo {

}

public class PublicBase {
  protected Foo MyFoo { get; set; }
}

In the case here, I have an internal type that I want to expose on a class, but I only want to expose it to derived types. Since the type is internal, that implicitly means derived types in the same assembly. External types can still legitimately inherit from this type, but they won't need to use this member.

In this situation I'm stuck: I can't use protected, nor can I use protected internal.

Instead, I have to use internal, which incorrectly broadcasts to other members of my team that it should be used from code outside the class. Sure I can stick a comment on it (and even stick the EditorBrowsableAttribute of Never on it, but that would hide it from internal inheritors too) - but it's not the same.

As it is, the only way I can achieve this is to hack the assembly with an IL rewrite after the build - but I need this visibility (or lack of it) at compile-time, not after it's built.

Ultimately, arguments about "what keyword(s) would it use" or "how would it be implemented" are irrelevant to me: I'm the programmer, not the C# language designer.

Equally, I have to say arguments like "Well, protected internal is confusing enough for many" are also irrelevant. There are so many developers I've come into contact with, either in person or virtually, who don't understand things like ?: or generic constraints - guess what, they don't use them! That doesn't mean I shouldn't.

So yes I understand the reasons for not implementing it - but I disagree with them - therefore my answer for why C# doesn't support it is because the C# designers got it wrong.

And yes I'm ready for the heat that might bring to my door :)

Andras Zoltan
  • 41,961
  • 13
  • 104
  • 160
2

So why C# should not support it?

Wrong question. The question should be "why should C# support protected and internal?"

Keep in mind, the natural state of a feature is for it to not be implemented. Implementing a feature is very expensive in terms of resources, testing, and, let's not forget, opportunity cost (meaning it displaces other features). So to overcome this expense, there had better be an extremely clear benefit for implementing a feature that overcomes these costs.

In particular, what is the value of protected and internal? There really is no good reason to restrict accessibility only to derived classes in the same assembly.

IMO it's odd the CLR supports it, but it does. That doesn't mean that C# needs to though.

jason
  • 236,483
  • 35
  • 423
  • 525
  • I can think of plenty of use cases where you are developing an object hierarchy within a single assembly, such as a Template Method setup, where basic processing logic exists in the base class but implementation details for that process lie in derived classes. Make them internal, and that communicates to other coders (present and future) that this detail is something they can use outside the class hierarchy when it shouldn't be. Make them protected, and your code is vulnerable to "assembly injection", where someone can derive your base class from his own assembly even if he can't change yours. – KeithS Jul 12 '19 at 19:02
0

As far as I know you can use intersection of protected and internal access modifiers but not with the interpretation you want (maybe because of what Henk said):

  1. Protected: The type or member can only be accessed by code in the same class or struct, or in a derived class.

  2. Internal: The type or member can be accessed by any code in the same assembly, but not from another assembly.

  3. Protected Internal: The type or member can be accessed by any code in the same assembly, or by any derived class in another assembly.

Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
Brazol
  • 435
  • 1
  • 6
  • 17
0

You can always do:

public MyExternallySealedClass
{
     internal MyExternallySealedClass() {...}

     ...
}

As long as you do not let any external consumer instantiate the object what would you care if they try deriving it? Short answer, the feature you request brings nothing new and you already have tools to do what you are requesting.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • Of course there is a workaround in your simple example. However, what about a class that is supposed to be subclassed in other libraries, but which has to feature a member that is supposed to be visible only to those subclasses that are defined within its original assembly? – O. R. Mapper Mar 03 '15 at 13:04
  • @O.R.Mapper I'd just implement it as `internal`, document it extensively, and make sure at code review that only derived classes are overrding said method. If its `internal` you have control over how things are implemented. It's not the perfect solution but this particular case is solvable with the language as it is and I dont find it reason enough to implement the requested feature which would bring little more to the table. You are basically using a language feature to enforce coding correctness in your own team...that seems fundamentally wrong. – InBetween Mar 04 '15 at 02:17
  • In my opinion, both the assumption that "If its internal you have control over how things are implemented." and the apparent intention to keep internal APIs (that only you access yourself) any less tidy (in terms of relative accessibility of identifiers and such) than public APIs (that external people will access) are extremely bad practice, but I agree C# unfortunately does not provide the means to do it better. – O. R. Mapper Mar 04 '15 at 09:32