80

C# 7.2 introduces the private protected modifier.

I've always protected access to fields with properties, allowing access via the Get/Set methods as I typically don't want the internal state of my object modified by anything other than my own class.

I'm trying to understand why the C# language team have added this feature. After an extensive search on google, and reading and watching the 'what's new' media (I've watched the press release, details and video by Mads Torgerson), I am still none the wiser.

To me, this appears to allow a developer to break the Liskov Substitution principle, but this may be because I do not understand why this feature now exists.

I understand how it can be used, just not why - please can someone provide a real-world usage example rather than the contrived one in the MSDN documents?

Jay
  • 9,561
  • 7
  • 51
  • 72
  • 4
    Are you sure you understand what this modifier actually does? – Evk Nov 22 '17 at 09:03
  • Probably because the CLR supports it, see `MethodAttributes.FamANDAssem`. C# already supported `internal protected` which is `MethodAttributes.FamORAssem`, it makes sense to be exhaustive – Lucas Trzesniewski Nov 22 '17 at 09:06
  • In what way do you think it breaks the LSP? – Jon Skeet Nov 22 '17 at 09:06
  • 1
    It's very similar to `protected` but with one important difference: if a class is derived from it but in another assembly, it cannot access this member whereas `protected` is not restricted to the same assembly. – Tim Schmelter Nov 22 '17 at 09:07
  • 6
    Here's an example of where I plan to use it, if it's any help: https://github.com/GoogleCloudPlatform/google-cloud-dotnet/blob/master/apis/Google.Cloud.Firestore/Google.Cloud.Firestore/Query.cs#L51 – Jon Skeet Nov 22 '17 at 09:07
  • @JonSkeet and why not make `Query` abstract if you don't want to allow to instantiate it directly (which would be implied with `private protected`)? – Evk Nov 22 '17 at 09:25
  • 2
    @Evk: Because I *do* want to instantiate it directly from within Query. It's fine for Query to be a concrete class, and it's fine to have a subclass - but only within the same assembly. It's not fine for other code to create instances of `Query`. `private protected` would give me *exactly* what I want. – Jon Skeet Nov 22 '17 at 09:27
  • @JonSkeet I didnt say it broke the LSP, I said that I thought it could allow a dev to break the LSP. I was thinking that you could somehow change the behaviour of the base class to do something undesirable by modifying a field (and the way I work - fields are strictly 'internal state'). Like I said - it is just the way it appears to me as I don't have a good understanding of why it'd be used as yet. – Jay Nov 22 '17 at 09:59
  • @Jay: Fair point on my misreading. But the ability to violate LSP has always been available. A dev can make a field public. Why does introducing one more level of access (which allows you to be *more* private than you can in some situations) allow the developer to break the LSP any more than they can now? It allows them to *avoid* that, by giving more control. – Jon Skeet Nov 22 '17 at 10:00
  • @JonSkeet Yes, what you say is true, a dev can make a field public (though I personally never do) - maybe there is no reason to be concerned. My reason for asking this question is that I am having trouble in understanding the need for this kind of access modifier, so now that I have a lunch break, I can read through all the comments and answers and see if I can understand why people are using or planning to use this new feature. Maybe Evk was right - maybe I have misunderstood what this modifier does. From the looks of it, I've got a bit to read! :) Thanks to all who have taken time to comment – Jay Nov 22 '17 at 12:47
  • 2
    See https://blogs.msdn.microsoft.com/ericlippert/2008/04/24/why-cant-i-access-a-protected-member-from-a-derived-class-part-three/ for some thoughts on this. There is a reason why it took fifteen years for the feature to make it close enough to the top of the priority list to get implemented: *it's not a very compelling, interesting or useful feature*. – Eric Lippert Nov 29 '17 at 01:15
  • @EricLippert +1 for your [blog](https://blogs.msdn.microsoft.com/ericlippert/2008/04/24/why-cant-i-access-a-protected-member-from-a-derived-class-part-three/), I loved the idea of `proternal or intected (The former sounds very positive; the latter, like bad news from a dentist.)` as possible names from all the way back in 2008! It gave me a laugh this morning! – Jay Nov 29 '17 at 08:42

4 Answers4

89

Before C# 7.2 we had protected internal modifier. This really means protected OR internal, that is - member A is accessible to child classes and also to any class in the current assembly, even if that class is not child of class A (so restriction implied by "protected" is relaxed).

private protected really means protected AND internal. That is - member is accessible only to child classes which are in the same assembly, but not to child classes which are outside assembly (so restriction implied by "protected" is narrowed - becomes even more restrictive). That is useful if you build hierarchy of classes in your assembly and do not want any child classes from other assemblies to access certain parts of that hierarchy.

We can take example that Jon Skeet provided in comments. Suppose you have class

public class MyClass {

}

And you want to be able to inherit from it only in current assembly, but do not want to allow to instantiate this class directly except from within this class hierarchy.

Inheriting only within the current assembly may be achieved with internal constructor

public class MyClass {
    internal MyClass() {
    }
}

Preventing direct instantiation except withing current class hierarchy may be achieved with protected constructor:

public class MyClass {
    protected MyClass() {
    }
}

And to get both - you need private protected constructor:

public class MyClass {
    private protected MyClass() {
    }
}
Tomas Kubes
  • 23,880
  • 18
  • 111
  • 148
Evk
  • 98,527
  • 8
  • 141
  • 191
  • 1
    @TimSchmelter they are similar in a sense they both involve restrictions about child classes (protected) and about current assembly (internal). They just combine those restrictions in a different way (and vs or). – Evk Nov 22 '17 at 09:18
  • Sorry, deleted my comment because opinion based. But i still think that `protected` is "more similar" than `protected internal`(very confusing access modifier because public assembly wise). The `protected` access modifier has the same contract: only accessible within same type or types derived from this. But it's scope is not limited to this assembly as opposed to `private internal`. So if a member is `protected` but you have to avoid that it's accessible from outside of this assembly you need `private protected`. – Tim Schmelter Nov 22 '17 at 09:18
  • 1
    So, this much I pretty much understood from reading the [MSDN page](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private-protected). What I'm not getting is *why* you'd ever want to do what they describe - which is to access a field on a base class from the derived class (in the same assembly) without introducing a property. If the example was left as yours is, then it makes perfect sense (and I liked the way you describe the difference between protected internal and private protected). Maybe I am just biased against the MSDN example! – Jay Nov 22 '17 at 13:07
  • @Jay well you should not expect much real-world sense from MSDN examples (as I understand your main complain is they are using protected field, not even related to whether it is just protected or "private protected"). After all it's not example of best class design practices - just illustrates what "private protected" does. – Evk Nov 22 '17 at 13:12
  • Yes, you are most likely correct, and I liked you example which confirmed what I had understood. So marking this as the answer. Thanks for taking the time. – Jay Nov 22 '17 at 13:44
  • Am I the only one who thinks the keyword `private` in `private protected` makes things very confusing? If what it does is essentially combining `internal` and `protected`, why call it `private protected`? Too bad `internal protected` already means something else, but they really should've come up with something better... – Rudey Nov 28 '17 at 21:20
  • 1
    @RuudLenders: This argument went on for a long time; I was holding out for "proternal" myself, but for some reason that was thought to be godawful. You and everyone else were invited to participate in the design process; no one came up with anything better, and apparently you haven't either. See https://roslyn.codeplex.com/discussions/541194 for the discussion. – Eric Lippert Nov 29 '17 at 01:19
38

For two-word access modifiers I have this concept - the first accessor is related to another assembly, the second one to that assembly in which it was defined.

protected internal

  • protected in another assembly: accessible only in the child classes.

  • internal in the current assembly: accessible by everyone in the current assembly.

private protected

  • private in another assembly: is not accessible.
  • protected in the current assembly: accessible only in the child classes.
Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112
  • 1
    Super, it's really easy and really makes sense. It helped me to get the idea of all this confusing thing. Thank you! – Andrew Dashkov Sep 04 '20 at 13:41
  • It may confuse some people at first, it definitely did to me, because I couldn't grasp why `internal and protected` was defined as `private protected`, and then `internal protected` meant another thing. I find it easy to understand it this way: **`private protected` == internal AND protected** while **`internal protected` == internal OR protected** – That Marc Jun 30 '21 at 14:11
  • @ThatMarc Yeah I was thinking this was the dumbest naming choice at first, but now it makes sense! The docs really should clarify it better. – rshea0 Aug 10 '23 at 21:17
9

Lets suppose that you have an internal class called SomeHelper that you want to use as part of the implementation of a public abstract base class:

public abstract class Test
{
    // Won't compile because SomeHelper is internal.
    protected SomeHelper CreateHelper()
    {
        return new SomeHelper();
    }

    public int Func(int x)
    {
        var helper = CreateHelper();
        return helper.DoSomething(x);
    }
}

internal class SomeHelper
{
    public virtual int DoSomething(int x)
    {
        return -x;
    }
}

This won't compile because you cannot have a protected method returning an internal type. Your only recourse is to not use SomeHelper in that way, or to make SomeHelper public.

(You could make SomeHelper a protected inner class of Test, but that's not going to work if SomeHelper is intended for use by other classes that don't derive from the base class.)

With the introduction of the private protected feature, you can declare CreateHelper() like so:

private protected SomeHelper CreateHelper()
{
    return new SomeHelper();
}

Now it will compile, and you don't have to expose your internals.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • 1
    You can delcare your `SomeHelper` as `protected` inner class of `Test`, then it will compile (about "Your only recourse..."). – Evk Nov 22 '17 at 09:20
  • @Evk Ah yes, I'll add that (but then it's not using `SomeHelper` "in that way", of course, which is what I really meant). – Matthew Watson Nov 22 '17 at 09:24
  • this may be quite useful as well – NSGaga-mostly-inactive Nov 22 '17 at 09:46
  • Not "as well". This is indeed the real world usage example. Passing and returning internal types to/from my own hierarchy protected methods has been a problem for many years. The workaround was to mark such methods as `internal` instead of logically `protected` and use coding discipline to not access them from outside the hierarchy. Sample provided in @Evk answer was never causing issues because it is solved by making the base class `abstract` with only `internal` constructors. – Ivan Stoev Dec 09 '17 at 02:12
  • @IvanStoev note that it's not my example but is taken from real world Jon Skeet's project. Base class cannot be abstract in that case because you need to instantiate it (but only from this class and subclasses). – Evk Dec 09 '17 at 07:43
  • @Evk Jon Skeet is not from "real world" though :) But seriously, with all my respect I think his class is quite unusual. Yes, `private protected` does what he needs, but Matthew example as well as internal type arguments of protected methods is something that we were catching all the time. Anyway, the whole question doesn't make any sense to me - if you don't see why is something needed, then you simply don't need it, so I'm taking off. – Ivan Stoev Dec 10 '17 at 13:15
0

protected internal implies to "protected or internal" - any type/member defined with this access modifier can be accessed in the following scenarios - (A) in the same assembly, (B) class which is defined in another assembly and derives from the container class

private protected implies to "protected and internal" - any type/member defined with this access modifier can be accessed in the following scenario - class that inherits from the container class and belongs to the same assembly