Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Access Modifiers for Beginners

0.00/5 (No votes)
6 Aug 2013 4  
Understand access modifiers before using them.

Introduction

This article is for beginners who have just started programming. Here I will show you how access modifiers help us design a class and when and why we use which modifier.

Background

If you search for the words "access modifiers" on the internet, you will find lots of references. I did the same and I am showing the below from MSDN.

  • public: Access is not restricted.
  • private: Access is limited to the containing type.
  • Internal: Access is limited to the current assembly.
  • protected: Access is limited to the containing class or types derived from the containing class.
  • protected internal: Access is limited to the current assembly or types derived from the containing class.

Using the Code

So let's start step by step by using a case study.

  • Case: Design a Customer class that will have id, name, reward-point variables. Id will be a random number; for general customer the reward point will always be 500, and for VIP customer it will be 1500. Also a print method is needed for each customer type which will show the output of the customer.
  • Analysis: So from the requirement, if we separate things, then we find the work to do is:
  1. Customer class with {private Id, public: Name, protected : RewardPoint}
  2. GenaralCustomer and VIPCustomer which inherits Customer Class
  3. Client for each customer type class which gives the name of the customer and calls the print method.

The below code is for analysis #1:

namespace SameAssembly
{
    public class Customer
    {
        private int Id {get;set;} /*private : Access is limited to the containing type.*/
        public string Name {get;set;}/*public : Access is not restricted.*/
        protected int RewardPoint{get;set;}/*protected : 
        			*Access is limited to the containing class 
                    * or types derived from the containing class.*/
        public Customer()
        {
            Id = new Random().Next();
        }

        /*internal :Access is limited to the current assembly or types. */
        internal virtual void PrintCustomerInfo()  
        {
            Console.WriteLine("\t\t\t\t ID:{0} \n\n \t\t\t\t 
            Name:{1} \n\n \t\t\t\t RewardPoint:{2} \n\n", Id, Name, RewardPoint);
        }
    }
}

The below code is for analysis #2 for GeneralCustomer:

namespace SameAssembly
{
    public class GeneralCustomer : Customer
    {
        internal string CustomerType
        {
            get { return "******** FOR GENERAL CUSTOMER ****************"; }
        }
        public GeneralCustomer()
        {
            RewardPoint = 500;
        }

        internal override void PrintCustomerInfo()
        {
            Console.WriteLine("\n\n\t\t\t" + CustomerType + "\n\n\t\t\t");
            base.PrintCustomerInfo();
        }
    }
} 

The below code is for analysis #3 client for GeneralCustomer:

namespace SameAssembly
{
    public class ClientForGeneral
    {
        public void Print()
        {
            var generalCustomer = new GeneralCustomer();
            generalCustomer.Name = "Mr Jhon";
            generalCustomer.PrintCustomerInfo();
        }
    }
}

If you look at the above Customer class, you see that ID is private. Why? Because we will not allow any other class to access it and also not even from the instance of the Customer class, we can only access it from the body of the Customer class where it is declared. So we assign it in the constructor of the Customer class. In short, we say "Access is limited to the containing type".

Name is public. Why? Because we allow access from everywhere. It can be accessed from a derived type or by an instance of Customer in the same assembly or a different assembly and also from the same content type. in short, we say "Access is not restricted".

Rewardpoint is protected. Why? Because we allow the access from its own containing class and also from the derive type in any assembly but not from the instance of base or derive type. One word we say "Access is limited to the containing class * or types derived from the containing class.";

PrintCustomerInfo() is internal. Why? Because we allow the access in the same assembly so that any class that is in the same assembly as the Customer class that inherits Customer will be able to override the method. In short, we say "Access is limited to the current assembly".

What does same assembly and different assembly mean?

Look at the picture below. Here my Customer class and Generalcustomer class are in the same assembly. Both the classes are in the same Class Library named SameAssembly and also share the same namespace. So we can say they are in the same assembly. ClientForVip and VipCustomer are in the same namespace/library. If Customer class is used in the VipCustomer class, then we can say that it is using different assemblies.

Notice both the members of the Customer class rewardpoint and PrintCustomerInfo can easily be accessed from the GeneralCustomer class. rewardPoint is protected so it can easily be accessed from the derived type and PrintCustomerInfo is internal so GeneralCustomer can access it because it is in the same assembly.

The below code is for analysis #2 for VIPlCustomer:

The code is:

namespace DifferentAssembly
{
    public class VipCustomer : Customer
    {
        internal string CustomerType
        {
            get
            {
                return "******** FOR VIP CUSTOMER ****************";
            }
        }
        public VipCustomer()
        {
            RewardPoint = 1500;
        }
        internal  override void PrintCustomerInfo()
        {
            Console.WriteLine("\n\n\t\t\t" + CustomerType+ "\n\n\t\t\t");
            base.PrintCustomerInfo();
        }        
    }
}

Here is the trick. I place the VIPCustomer class in a different class library than the Customer class. From there, I want to access my Customer class members in the derived class VIPCustomer. So will the above code compile? No, it will give you the below compiled error:

Error 1 'DifferentAssembly.VipCustomer.PrintCustomerInfo()': 
no suitable method found to override 
J:\Access Modifiers\AccessModifiers\DifferentAssembly\VipCustomer.cs 18 33 DifferentAssembly 

Why? Because rewardpoint is OK, accessible from any derived type as it is protected. But PrintCustomerInfo can't access from another assembly as it is defined as internal. As I said earlier:

PrintCustomerInfo() is internal. Why? Because we allow the access in the same assembly, so that any class that is in the same assembly as the customer class that inherits customer class will be able to override the method.

So what's the solution? Will we make it protected, does it solve our issue? No, not at all. It will raise another issue on our client class ClientForGeneral because we can't access PrintCustomromerInfo from there if it's protected. The below line will give an error.

generalCustomer.PrintCustomerInfo();  

So what's the solution? The solution is protected internal. We need to change the PrntCustomerInfo method of the Customer class like below:

/*protected internal :Access is limited to the current assembly or types 
 * derived from the containing class. */
protected internal virtual void PrintCustomerInfo()  
{
    Console.WriteLine("\t\t\t\t ID:{0} \n\n \t\t\t\t 
    Name:{1} \n\n \t\t\t\t RewardPoint:{2} \n\n", Id, Name, RewardPoint);
}

In the current assembly, the client ClientForGeneral will have no problem at all to access PrintCustomerInfo through the object because it's in the same assembly; here it will act as internal.

So the override method in GeneralCustomerClass will be like below:

protected  internal override void PrintCustomerInfo()
{
    Console.WriteLine("\n\n\t\t\t" + CustomerType+ "\n\n\t\t\t");
    base.PrintCustomerInfo();
}

In VipCustomer, it will act as protected like below. Here you can't use protected internal; only protected modifier is valid here.

protected  override void PrintCustomerInfo()
{
    Console.WriteLine("\n\n\t\t\t" + CustomerType+ "\n\n\t\t\t");
    base.PrintCustomerInfo();
} 

If you write it protected internal, you will receive the compile error:

Error 1 'DifferentAssembly.VipCustomer.PrintCustomerInfo()': cannot change access
 modifiers when overriding 'protected' inherited member
 'SameAssembly.Customer.PrintCustomerInfo()' 
J:\Access Modifiers\AccessModifiers\DifferentAssembly\VipCustomer.cs 17 42 DifferentAssembly

So the compiler will easily assume the derived type, it will act as protected not protected internal.

Points of Interest

What about the client class ClientForVip? How it will access the PrintCustomerInfo() method as it is now protected? We need to give some extra effort, we need another method that is accessible through that class instance.

internal void PrintVipCustomerInfo()
{
    PrintCustomerInfo();
} 

Now the client class can access PrintCustomerInfo through its internal method PrintVipCustomerInfo.

namespace DifferentAssembly
{
    class ClientForVip
    {
        public void Print()
        {
            var generalCustomer = new VipCustomer();
            generalCustomer.Name= "Mr Mark";
            generalCustomer.PrintVipCustomerInfo();
        }
    }
} 

If we add the reference of SameAssembly and DifferentAssembly to any console application and call the client of each type like below:

namespace AccessModifiers
{
    class Program
    {
        static void Main(string[] args)
        {
            var generalClient = new ClientForGeneral();
            generalClient.Print();
            
            var vipClient = new ClientForVip();            
            vipClient.Print();
            Console.ReadKey();
        }
    }
}

It gives the following output:

I found most of developers confused about the use of internal and protected internal. Hope this article helps them to clear their understanding about Access Modifiers.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here