• Wrapping up of data & methods into a single unit (called class) is known as encapsulation.
• The data is not accessible to the outside world and only those methods, which are wrapped in the class, can access it.
• Encapsulation provides a way to preserve the integrity of state-data.
• For example, assume we have created a class named DBReader having methods open() and close():
DBReader d=new DBReader(); d.open(“C:\MyDatabase.mdf”); d.close();
• The class DBReader has encapsulated the inner details of locating, loading, manipulating and closing data file. But, the object user need not worry about all these.
• Closely related to notion of encapsulation is data hiding. We do this by making data members as
private.
• The private data can be modified only through the public member functions of that class. • C# provides following two techniques to manipulate private data members:
1) Enforcing Encapsulation Using Traditional Accessors & Mutators
• Consider, if we wish to provide safe access to the Employee's internal "fullName" data member, we would write
public class Employee {
private string fullName;
public string GetFullName() //Accessor {
return fullName; }
public void SetFullName(string s) //mutator {
//remove any illegal characters(# ! ?)
//check maximum length before making assignment fullName=s;
} }
• In the above example, GetFullName() and SetFullName() encapsulate a private string named "fullName". The calling logic is as follows
public static int Main(string[] args) {
Employee p=new Employee(); p.SetFullName("John");
Console.WriteLine("Employee name is {0}",p.GetFullName());
p.fullName; //error occurs,can't access private data from an object instance return 0;
}
2) Enforcing Encapsulation Using Class Properties • Classes can define properties.
• Properties are used to simulate publicly accessible-points of data.
• Rather than requiring the user to call 2 discrete methods to get and set the state-data, the user is able to call a single named field.
• To illustrate, we have provided a property named "EmpID" that wraps the internal "empID" member variable
public class Employee //custom property for EmpID data point {
private int ID;
public int EmpID //property for ID data point {get{return ID;}
set {ID=value;} }
public static int Main(string[] args) {
Employee p=new Employee();
EmpID=81; //set the value Console.WriteLine("person ID is {0}",p.EmpID); return 0;
Greatness arrives for those who are never satisfied with what is, no matter how nice it looks.
• A property is composed of a get block(accessor) and set block(mutator). The "value" keyword represents the RHS of the assignment.
• "value" is also an object. However, the underlying type of object depends on which sort of data it represents.
READ-ONLY AND WRITE-ONLY PROPERTIES
• When building custom properties, we can configure a read-only property. To do so, simply build a property without a corresponding set block. Likewise, if we wish to have a write-only property, omit the get block.
Eg:
public class Employee {
private string empSSN;
public Employee(string fullName, int empID, float currPay, string SSN) { this.fullName=fullName; this.empID=empID; this.currPay=currPay; this.empSSN=SSN; }
//set block omitted to provide read-only property public string SSN{ get{ return empSSN;}} }
UNDERSTANDING STATIC PROPERTIES
• The static members are bound to a given class, not an instance of that class. For e.g., assume that the 'Employee' type defines a point of static data to represent the name of organization. For this, we may define a static property as follows.
//static properties must operate on static data public class Employee
{
private static string companyName; public static string Company {
get {return CompanyName;} set {companyName=value;} }
}
//set and get the name of company public static int Main(string[] args) {
Employee.Company="intel";
Console.WriteLine("these people work at {0}", Employee.Company); }
PSEUDO ENCAPSULATION: CREATING READ-ONLY FIELDS
• Read-only fields offer data preservation via the "readonly" keyword. E.g.: assume we have a read- only field named SSNField that offers an alternative manner for the caller to obtain an employee's SSN.
public class Employee {
public readonly string SSNField;
public Employee(string fullName,int empID,float currPay,string SSN) {
thisfullName=fullName; this.empID=empID; this.currPay=currPay; this.empSSN=SSN;
SSNfield=SSN; //assign read only field }
}
Behind extraordinary achievement, you will always discover extraordinary effort.
KEEPING FAMILY SECRETS: THE "PROTECTED" KEYWORD
• When a base class defines protected data or protected methods, it is able to create a set of members that can be accessed directly by any descendent.
• The benefit of defining protected members i a base class is that derived types no longer have to access the data using public methods or properties.
• The main downfall: when a derived type has direct access to its parent's internal data, it is very possible to accidentally break existing business rules.
• As far as the object user is concerned, protected data regarded as private (as the user is "outside" of the family).
public class Employee {
protected string fullName; protected int empID;
}
PREVENTING INHERITANCE: SEALED CLASSES • Consider the following figure 4-10.
• Here, PTSSalesPerson is a class representing a part-time SalesPerson. To prevent other classes from extending this class (PTSalesman), we make use of "sealed" keyword.
public sealed class PTSalesPerson: SalesPerson {
public PTSalesPerson(string fullName,int empID): base(fullName,empID) {
//some constructor logic }
}
• Because PTSalesPerson is sealed, it cannot serve as a base class to any other type. Thus, if we attempted to extend PTSalesPerson, we receive a compiler error.
• The "sealed" keyword is most useful when creating standalone utility classes. For e.g., the "String" class defined in the "System" namespace has been explicitly sealed.
public sealed class string: Object IComparable,ICloneable
You can expect only that which you inspect.