Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A protected internal method in C# is a class member whose access level is the logical union of the protected and internal access modifiers. It can be invoked by any code within the same assembly in which it is declared, or by any derived class located in a different assembly. Unlike private protected (which requires a caller to be both in the same assembly and a derived class), protected internal grants access if either condition is met.

Syntax

The modifiers can be applied in either order (protected internal or internal protected), though protected internal is the standard convention.
public class BaseClass
{
    protected internal void ProcessData()
    {
        // Method implementation
    }
}

Access Rules and Compilation Boundaries

The compiler enforces the following strict access boundaries for a protected internal method:
  1. Within the Declaring Assembly: The method behaves exactly like an internal method. It can be accessed by any type (class, struct, etc.) within the same compiled .dll or .exe, regardless of inheritance.
  2. Outside the Declaring Assembly: The method behaves exactly like a protected method. It is only accessible to types that derive from the declaring class. Furthermore, within that external derived class, the method can only be accessed through an instance of the derived class type (or a type derived from it), not through an instance of the base class type.

Code Visualization

The following example demonstrates the compiler’s behavior across two distinct assemblies.
// =========================================
// Assembly A
// =========================================
public class BaseClass
{
    protected internal void Execute() 
    { 
    }
}

public class UnrelatedClassInSameAssembly
{
    public void InvokeMethod()
    {
        var instance = new BaseClass();
        // ALLOWED: Satisfies the 'internal' condition.
        instance.Execute(); 
    }
}

// =========================================
// Assembly B
// References Assembly A
// =========================================
public class DerivedClass : BaseClass
{
    public void InvokeMethod()
    {
        // ALLOWED: Satisfies the 'protected' condition.
        this.Execute(); 
        
        var baseInstance = new BaseClass();
        // ERROR CS1540: Cannot access protected member via a qualifier of type 'BaseClass'.
        // baseInstance.Execute(); 
    }
}

public class UnrelatedClassInDifferentAssembly
{
    public void InvokeMethod()
    {
        var instance = new BaseClass();
        // ERROR CS0122: 'BaseClass.Execute()' is inaccessible due to its protection level.
        // instance.Execute(); 
    }
}

Inheritance and Overriding

When a protected internal virtual method is overridden in a derived class located in a different assembly, the overriding method must be declared as protected. It cannot be declared as protected internal because doing so would illegally expand the method’s visibility to unrelated, non-derived classes within the derived class’s assembly (Assembly B).
// Assembly A
public class BaseClass
{
    protected internal virtual void Initialize() { }
}

// Assembly B
public class DerivedClass : BaseClass
{
    // Must be 'protected', not 'protected internal'
    protected override void Initialize() 
    { 
        base.Initialize();
    }
}

The [InternalsVisibleTo] Exception

The strict overriding rule changes completely if the base assembly explicitly grants internal visibility to the derived assembly using the [InternalsVisibleTo] attribute. If Assembly A uses [assembly: InternalsVisibleTo("AssemblyB")], the derived class in Assembly B is granted visibility into Assembly A’s internal scope. Because the derived class now sees the internal modifier of the base method, the compiler mandates that the override must be declared as protected internal to match the base signature’s effective accessibility.
// Assembly A
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("AssemblyB")]

public class BaseClass
{
    protected internal virtual void Initialize() { }
}

// Assembly B
public class DerivedClass : BaseClass
{
    // Must be 'protected internal' due to InternalsVisibleTo
    protected internal override void Initialize() 
    { 
        base.Initialize();
    }
}
Master C# with Deep Grasping Methodology!Learn More