Interface properties
Properties can be declared on the interface. Here is an example of an interface indexer accessor:
public interface ISampleInterface { // Property declaration: string Name { get; set; } }
The accessor for the interface attribute does not have a body. Therefore, the purpose of the accessor is to indicate whether the attribute is read-write, read-only, or write-only.
In this example, the interface IEmployee has a read-write attribute Name and a read-only attribute Counter. The Employee class implements the IEmployee interface and uses both properties. The program reads the name of the new employee and the current number of the employee and displays the employee name and the calculated employee number.
You can use a fully qualified name of a property, which references the interface that declares members. For example:
string { get { return "Employee Name"; } set { } }
This is called an explicit interface implementation (C# Programming Guide). For example, if the Employee class implements two interfaces, ICitizen and IEmployee, and both interfaces have Name attributes, then explicit interface member implementations are required. That is, the following attribute declaration:
string { get { return "Employee Name"; } set { } }
Implement the Name property on the IEmployee interface, and the following statement:
string { get { return "Citizen Name"; } set { } }
Implement the Name property on the ICitizen interface.
interface IEmployee { string Name { get; set; } int Counter { get; } } public class Employee : IEmployee { public static int numberOfEmployees; private string name; public string Name // read-write instance property { get { return name; } set { name = value; } } private int counter; public int Counter // read-only instance property { get { return counter; } } public Employee() // constructor { counter = ++counter + numberOfEmployees; } } class TestEmployee { static void Main() { ("Enter number of employees: "); = (()); Employee e1 = new Employee(); ("Enter the name of the new employee: "); = (); ("The employee information:"); ("Employee number: {0}", ); ("Employee name: {0}", ); } }
For example, here we enter:
210 Hazem Abolrous
Then the sample output
Enter number of employees: 210 Enter the name of the new employee: Hazem Abolrous The employee information: Employee number: 211 Employee name: Hazem Abolrous
Limit accessibility
The get and set parts of a property or indexer are called "accessors". By default, these accessors have the same visibility or access level: the visibility or access level of the attributes or indexers they belong to. However, sometimes it can be useful to restrict access to one of these accessors. Usually, limiting the accessibility of the set accessor while keeping the get accessor publicly accessible. For example:
private string name = "Hello"; public string Name { get { return name; } protected set { name = value; } }
In this example, the property named Name defines a get accessor and a set accessor. The get accessor accepts the accessibility level of the property itself (public in this example), and for the set accessor, it is explicitly restricted by applying a protected access modifier to the accessor itself.
Restrictions on access modifiers for accessors
The use of access modifiers for properties or indexers is subject to the following conditions:
Accessor modifiers cannot be used for interfaces or explicit interface members implementations.
Accessor modifiers can only be used if the property or indexer has both set and get accessors. In this case, only modifiers are allowed for one of the accessors.
If the property or indexer has an override modifier, the accessor modifier must match the accessor (if any) of the override accessor.
The accessibility level of an accessor must have stricter restrictions than the accessibility level of the property or indexer itself.
Rewrite access modifiers for accessors
When rewriting properties or indexers, the rewritten accessor must be accessible to rewrite the code. In addition, both the attribute/indexer and accessor accessibility levels must match the corresponding rewritten attribute/indexer and accessor. For example:
public class Parent { public virtual int TestProperty { // Notice the accessor accessibility level. protected set { } // No access modifier is used here. get { return 0; } } } public class Kid : Parent { public override int TestProperty { // Use the same accessibility level as in the overridden accessor. protected set { } // Cannot use access modifier here. get { return 0; } } }
Implement the interface
When using an accessor to implement an interface, the accessor cannot have access modifiers. However, if an interface is implemented using one accessor (such as get), another accessor can have access modifiers, as shown in the following example:
public interface ISomeInterface { int TestProperty { // No access modifier allowed here // because this is an interface. get; } } public class TestClass : ISomeInterface { public int TestProperty { // Cannot use access modifier here because // this is an interface implementation. get { return 10; } // Interface property does not have set accessor, // so access modifier is allowed. protected set { } } }
Accessor accessibility domain
If access is used for the accessor, the accessibility domain of the accessor is determined by the modifier.
If access modifiers are not used for the accessor, the accessibility domain of the accessor is determined by the property or the accessibility level of the indexer.
The following example contains three classes: BaseClass, DerivedClass, and MainClass. Each class's BaseClass, Name, and Id have two properties. This example demonstrates how to hide the DerivedClass' Id property through the Id property of BaseClass when using restrictive access modifiers such as protected or private. Therefore, when assigning a value to this property, the properties in the BaseClass class are called. Replacing the access modifier with public will make the property accessible.
The example also demonstrates how restrictive access modifiers (such as private or protected) on the set accessor for the Name property of DerivedClass prevent access to the accessor and generate errors when assigning values to it.
public class BaseClass { private string name = "Name-BaseClass"; private string id = "ID-BaseClass"; public string Name { get { return name; } set { } } public string Id { get { return id; } set { } } } public class DerivedClass : BaseClass { private string name = "Name-DerivedClass"; private string id = "ID-DerivedClass"; new public string Name { get { return name; } // Using "protected" would make the set accessor not accessible. set { name = value; } } // Using private on the following property hides it in the Main Class. // Any assignment to the property will use Id in BaseClass. new private string Id { get { return id; } set { id = value; } } } class MainClass { static void Main() { BaseClass b1 = new BaseClass(); DerivedClass d1 = new DerivedClass(); = "Mary"; = "John"; = "Mary123"; = "John123"; // The property is called. ("Base: {0}, {1}", , ); ("Derived: {0}, {1}", , ); // Keep the console window open in debug mode. ("Press any key to exit."); (); } }
Output:
Base: Name-BaseClass, ID-BaseClass Derived: John, ID-BaseClass