- public: accessible anywhere any time.
- private: accessible within the the declared class.
- protected: accessible within the the declared or any derived class.
The last two are not as clear nor as common.
- internal: accessible within the current assembly
- protected internal: accessible within the current assembly or from a derived class, even if that derived class is in a different assembly.
One caveat is that you can compile multiple projects into one assembly using the Assembly linker tool.
To demonstrate internal and protected internal scope, we are going to have to create two dotnet core projects and link them together.
To demonstrate internal and protected internal scope, we are going to have to create two dotnet core projects and link them together.
In your command prompt, let's start by creating a root folder for our two projects, and navigate into it
mkdir pav.root
cd pav.root
now inside of pav.root let's create two dotnet core project, a Console app and a Linked library.
dotnet new console -n pav.console --use-program-main
dotnet new classlib -n pav.library
with our projects created, let's open up our pav.root folder in code, in the pav.root folder enter in
code .
finally with our root folder open, we are going to have to reference our pav.library project in our pav.console project.
dotnet add e:\learn\pav.root\pav.console\pav.console.csproj reference e:\learn\pav.root\pav.library\pav.library.csproj
your terminal should look similar to the following
Just to make sure that our classes are linked together, open the csproj file of your console app.
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\pav.library\pav.library.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
notice the ProjecctReference node in the ItemGroup.
With our two projects created, let's add two classes to the library project; Person and Employee
namespace pav.library;
public class Person : IComparable<Person>
{
// can be access from anywhere
public string Name { get; set; }
// can only be accessed within this assembly, only inside our library
protected DateTime BirthDate { get; set; }
// can accessed from anywhere
public Person(string Name, DateTime BirthDate)
{
this.Name = Name;
this.BirthDate = BirthDate;
}
// can only be accessed within this assembly, only inside our library
internal int GetAge()
{
DateTime today = DateTime.Today;
int age = today.Year - BirthDate.Year;
return BirthDate > today.AddYears(-age) ? --age : age;
}
// can be accessed within this assembly, or from any dereived type outside our assembly
protected internal virtual string Display() { return $"{Name} is {GetAge()}"; }
public int CompareTo(Person? other)
{
if (other != null)
return GetAge() - other.GetAge();
return 0;
}
}
public class Employee : Person
{
static int _runningID;
public int Id { get; private set; } = _runningID++;
public Employee(string Name, DateTime BirthDate) : base(Name, BirthDate) { }
protected internal override string Display() { return $"{base.Display()} with id:{Id}"; }
}
Let's try it out, let's instantiate instances of our person and employee classes in our console assembly and see what properties and functions we have access to, keep in mind that we need to add the using statement for our library in our console assembly.
using pav.library;
namespace pav.console;
class Program
{
static void Main(string[] args)
{
var pav = new Person("pav", new DateTime(1984, 1, 31));
var tom = new Employee("tom", new DateTime(1984, 1, 31));
Console.WriteLine(pav.Name);
Console.WriteLine(tom.Name);
}
}
Let's create a Student class inside our console assembly that derives from the Person class in our library assembly.
using pav.library;
namespace pav.console;
class Student : Person
{
public int StudentId { get; set; }
public Student(string Name, DateTime BirthDate, int studentId) : base(Name, BirthDate){
this.StudentId = studentId;
}
public string DisplayFromBase() =>
$"{base.Display()} years old with a student Id of {this.StudentId}";
}
class Program
{
static void Main(string[] args)
{
var pav = new Person("pav", new DateTime(1984, 1, 31));
var tom = new Employee("tom", new DateTime(1988, 8, 31));
Console.WriteLine(pav.Name);
Console.WriteLine(tom.Name);
var bob = new Student("bob", new DateTime(1995, 4, 15), 101388431);
Console.WriteLine(bob.DisplayFromBase());
}
}
in the above we created a Student Class that inherits from person, in our new Student class we created a functions called DisplayFromBase, in this function we call Person's implementation of the Display() function which has the scope of protected internal, meaning that it's not accessible on instances of Person, however it is available to classes that inherit from person.
Also notice that, in our Student class we do not direct access to the getAge() function, because it is scoped as simply internal, meaning that no access outside of our library assembly is available.