The New Private Protected Access Modifier

In a previous post we talked about the new in  keyword in C# 7.2, which got me going through the new features in C# and how they all fit together. One of these new features is the private protected  access modifier. Now you’ve heard of marking properties/variables with private , and you’ve heard of them being marked protected , but have you heard of them being marked private protected ?! Next level! Let’s take a look.

How Protected Currently Works

First, let’s look at a basic example of how the protected keyword can be used. A member that is marked with only protected, can only be accessed within derived classes, but the derived class can be in any assembly. So for example, in “assembly1” we have the following code :

public class BaseClass
{
	protected string BaseMember { get; set; }
}

public class DerivedClass : BaseClass
{
	void DoSomething()
	{
		var member = BaseMember;
	}
}

public class ServiceClass
{
	void DoSomething()
	{
		var baseClass = new BaseClass();
		var member = baseClass.BaseMember; // Error.
	}
}

In this example, our DerivedClass has no issues accessing the BaseMember because it has inherited the base class. However our ServiceClass throws a compile time error that it cannot access the member from an instantiated class. Makes sense.

In a second assembly, for arguments sake let’s call it “assembly2”, we create the create the following class :

class DerivedClassInAnotherAssembly : BaseClass
{
	void DoSomething()
	{
		BaseMember = "something";
	}
}

class ServiceClassInAnotherAssembly
{
	void DoSomething()
	{
		var baseClass = new BaseClass();
		var member = baseClass.BaseMember; // Error.
	}
}

This essentially has the same effect as what we did in assembly1. Our derived class still works even though it’s in another assembly, because protected doesn’t care about where the derived class is actually located, only that it’s inheriting from the base class. And our service is still broken as we would expected.

So that’s protected done.

How Internal Protected Works

So a little known access modifier that has been in the C# language for a while is internal protected . Now at first glance you might think that it’s an “and” type deal. Where the member is internal and protected e.g. It can only be accessed within the same assembly. But actually it’s an “or” situation. You can access the member if you are inside a derived class or you are within the same assembly.

Going back to our example. Inside assembly1 if we go ahead and change the BaseMember to be internal protected :

public class BaseClass
{
	internal protected string BaseMember { get; set; }
}

public class DerivedClass : BaseClass
{
	void DoSomething()
	{
		var member = BaseMember;
	}
}

public class ServiceClass
{
	void DoSomething()
	{
		var baseClass = new BaseClass();
		var member = baseClass.BaseMember; // Now has no issue. 
	}
}

We can now see that inside our ServiceClass, when we instantiate the instance of the BaseClass, we can now access the BaseMember. And our DerivedClass is still trucking along as per normal. This is where the “or” comes in.

If we head to our second assembly (assembly2). And recheck our code there :

class DerivedClassInAnotherAssembly : BaseClass
{
	void DoSomething()
	{
		BaseMember = "something";
	}
}

class ServiceClassInAnotherAssembly
{
	void DoSomething()
	{
		var baseClass = new BaseClass();
		var member = baseClass.BaseMember; // Error.
	}
}

Nothing has changed. Our DerivedClass can still access the BaseMember, but our ServiceClass that is instantiating up an instance cannot.

How Private Protected Works

Now we are onto the new stuff! Before we get into explanations, let’s keep running with our example and change our BaseClass to use private protected  and see how we go.

First assembly1 :

public class BaseClass
{
	private protected string BaseMember { get; set; }
}

public class DerivedClass : BaseClass
{
	void DoSomething()
	{
		var member = BaseMember;
	}
}

public class ServiceClass
{
	void DoSomething()
	{
		var baseClass = new BaseClass();
		var member = baseClass.BaseMember; // Error. 
	}
}

So we have changed our BaseMember to being private protected. Our DerivedClass still doesn’t have an issue, but our ServiceClass is throwing up an error at compile time again. So far, it’s working just like how protected has always worked.

Onto assembly2 :

class DerivedClassInAnotherAssembly : BaseClass
{
	void DoSomething()
	{
		BaseMember = "something"; // Error
	}
}

class ServiceClassInAnotherAssembly
{
	void DoSomething()
	{
		var baseClass = new BaseClass();
		var member = baseClass.BaseMember; // Error.
	}
}

What have we here!? So now in our second assembly, even our DerivedClass is now throwing up an error even though it is inheriting the BaseClass. Our ServiceClass is still in strife, so nothing has changed there.

From this we can see that using private protected  means basically what I originally thought internal protected  meant. It’s protected so that only derived classes can use it, but it’s also only for use within the same assembly.

If you haven’t already gathered, I’m not a big fan of the naming. The internal  keyword already sparks off a “only within this assembly” lightbulb in a developers head, so to then use the private  keyword to limit a member across assemblies seems like an odd choice. But internal protected  was already taken, so it’s a bit of a rock and a hard place.

What do you think?

In Chart Form

In case you are still a little confused (And because things are always better in chart form), here’s a handy chart to make things just that little bit easier.

Derived Class/Same AssemblyInstance/Same AssemblyDerived Class/Different AssemblyInstance/Different Assembly
protectedYesNoYesNo
internal protectedYesYesYesNo
private protectedYesNoNoNo

 

Leave a Comment