What is the use case for the (C# 7.2) “private pro

2019-01-16 22:40发布

问题:

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?

回答1:

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() {
    }
}


回答2:

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.



回答3:

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.