16 Mar 2024




Intermediate

In C#, the protected internal access modifier is a combination of two other access modifiers: protected and internal. It allows access to members within the same assembly (internal) or from derived classes (protected).

Here's what each of these modifiers means individually:

  1. protected: Members (fields, methods, properties, etc.) marked as protected are accessible within the containing class and from derived classes. They are not accessible from outside the class unless accessed through a derived class instance.

  2. internal: Members marked as internal are accessible within the same assembly but not from outside the assembly. An assembly in .NET is typically a .dll or .exe file. This means that any other code within the same project or assembly can access internal members.

Combining these two modifiers with protected internal means that the member is accessible:

  • From within the same assembly (because of internal),
  • From any derived class (because of protected), regardless of whether they are in the same assembly or a different one.

In summary, protected internal grants access to members from within the same assembly and from derived classes, whether they're within the same assembly or a different one. This provides a flexible level of access control, allowing for sharing among related classes within the same assembly while still maintaining encapsulation.

Example:

Let's say we have an assembly that contains a base class with a protected internal member, and another assembly that contains a derived class.

Assembly A:

// ClassLibraryA.dll

namespace AssemblyA
{
    public class BaseClass
    {
        // Protected internal member
        protected internal int ProtectedInternalMember { get; set; }

        // Constructor
        public BaseClass(int value)
        {
            ProtectedInternalMember = value;
        }
    }
}

Assembly B:

// ClassLibraryB.dll

using AssemblyA;

namespace AssemblyB
{
    // Derived class in a different assembly
    public class DerivedClass : BaseClass
    {
        // Constructor
        public DerivedClass(int value) : base(value)
        {
        }

        // Method to demonstrate accessing the protected internal member
        public void DisplayProtectedInternalMember()
        {
            // Accessing the protected internal member from the derived class
            Console.WriteLine($"Protected Internal Member value: {ProtectedInternalMember}");
        }
    }
}

In this example, BaseClass in AssemblyA has a protected internal member ProtectedInternalMember.

Now, let's create a console application to demonstrate how this works:

// ConsoleApplication.exe

using AssemblyB;
using System;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            // Creating an instance of the derived class
            DerivedClass derivedObj = new DerivedClass(10);

            // Accessing the protected internal member from the derived class method
            derivedObj.DisplayProtectedInternalMember();

            // Attempting to access the protected internal member from here will result in a compile-time error
            // Because it's not accessible from outside the assembly unless through a derived class.
            // Console.WriteLine($"Protected Internal Member value: {derivedObj.ProtectedInternalMember}");
        }
    }
}

In this example:

  • DerivedClass in AssemblyB inherits from BaseClass in AssemblyA.
  • The constructor of BaseClass initializes the ProtectedInternalMember with the value passed to it.
  • DerivedClass can access the ProtectedInternalMember directly within its method DisplayProtectedInternalMember(), demonstrating that the member is accessible to derived classes.
  • Attempting to access ProtectedInternalMember directly from the Main method of ConsoleApplication will result in a compile-time error because it's not accessible from outside the assembly unless through a derived class.
c-sharp
access-modifier