Visual C# Developer Center > Visual C# Forums > Visual C# Language > Interfaces and Abstract Classes
Ask a questionAsk a question
 

AnswerInterfaces and Abstract Classes

  • Wednesday, January 17, 2007 2:01 AMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,
    I am hoping someone can explain this to me.
    Lets say I have an abstract class called Employee, from Employee, the following classes are inherited, Manager and Cleaner
    Can someone explain to me how to incorporate an Interface for this scenario so my application can tell which type of object "Manager or Cleaner" its dealing with?

    Thanks

Answers

  • Wednesday, January 17, 2007 4:37 AMMark Dawson Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi,

      well this is my thought on interfaces and abstract classes, you want to have an abstract class when concrete classes will be sharing similar implementation details, like each employee has a name, that field can be stored in the abstract class and also the property to access that information can be in the abstract class.  So when you have similar classes that will share code use an abstract class, however if you have classes that are nothing to do with one another but share some aspect that they do not share a common ancestor then use an interface.  A good example of this is the IDisposable interface,  you use this when an object has some internal resource that needs to be explicitly cleaned up as soon as possible, so the interface has a single method called Dispose,  now you can apply this to any object since all objects will be different in how they dispose of their internal state, but you still want to be able to call objects as IDisposable types, hope that makes sence.

    An example of what I would do if I was you is shown below:

    using System;

    using System.Collections.Generic;

     

    namespace ConsoleApplication2

    {

        class Program

        {

            static void Main(string[] args)

            {

                Cleaner c = new Cleaner("bob", 5000);

                Manager m = new Manager("mike", 100000);

     

                Employee[] employees = new Employee[] { c, m };

                PrintEmployeeDetails(employees);

            }

     

            static void PrintEmployeeDetails(Employee[] employees)

            {

                foreach (Employee employee in employees)

                {

                    Console.WriteLine("Name=" + employee.Name + ", Salary=" + employee.Salary);

                }

            }

        }

     

        abstract class Employee

        {

            private string name;

            private int salary;

     

            protected Employee(string name, int salary)

            {

                this.name = name;

                this.salary = salary;

            }

     

            public string Name

            {

                get

                {

                    return this.name;

                }

            }

     

            public int Salary

            {

                get

                {

                    return this.salary;

                }

            }

        }

     

        class Manager : Employee

        {

            public Manager(string name, int salary)

                : base(name,salary)

            {

            }

        }

     

        class Cleaner : Employee

        {

            public Cleaner(string name, int salary)

                : base(name, salary)

            {

            }

        }

     

    }

     

     

    Mark.

All Replies

  • Wednesday, January 17, 2007 2:46 AMMark Dawson Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

      what are you trying to achieve.  The beauty of abstract classes are that you should not have to know what concrete type of object you are dealing with most of the time, you have some common interface which is defined in the abstract class which you call on the concrete instances i.e. a classic example would be:

    using System;

    using System.Collections.Generic;

    using System.Threading;

     

    namespace ConsoleApplication1

    {

        class Program

        {

            static void Main(string[] args)

            {

                Circle circle = new Circle();

                Square square = new Square();

     

                Shape[] shapes = new Shape[] { circle, square };

     

                DrawShapes(shapes);

            }

     

            public static void DrawShapes(Shape[] shapes)

            {

                //Do not care what shapes they are all this methods cares

                //about that it is responsible for drawing them all

                foreach(Shape shape in shapes)

                {

                    shape.Draw();

                }

            }

        }

     

        abstract class Shape

        {

            public abstract void Draw();

        }

     

        class Square : Shape

        {

            public override void Draw()

            {

                Console.WriteLine("Drawing square");

            }

        }

     

        class Circle : Shape

        {

            public override void Draw()

            {

                Console.WriteLine("Drawing circle");

            }

        }

    }

     

    If you really want to know the type then you can just do the following:

    MyClass x = new MyClass();

    if(x is MyClass)

    {

    }

     

    Mark.

  • Wednesday, January 17, 2007 3:40 AMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks Mark,
    What I am trying to do is something like this.
    after the employee logs in the with username and password, I want to be able to use retrieve all of his/her information. all employees inherit from the abstract class. I am convinced now that the best way to do this is by using an interface along with the abstract class but still can not think of a clear way of writting the code for it.


  • Wednesday, January 17, 2007 4:13 AMFigo FeiMSFT, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi, Sammy

    If you want to check if an object is compatible with a given type just use is keyword as mark said.

    Thanks

  • Wednesday, January 17, 2007 4:18 AMFigo FeiMSFT, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Ok,

    You may create an interface just called Login to define the login issue (get and set the password etc.). Then all the employee inherited the interface. That's my idea about it.

    Thank you

  • Wednesday, January 17, 2007 4:37 AMMark Dawson Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi,

      well this is my thought on interfaces and abstract classes, you want to have an abstract class when concrete classes will be sharing similar implementation details, like each employee has a name, that field can be stored in the abstract class and also the property to access that information can be in the abstract class.  So when you have similar classes that will share code use an abstract class, however if you have classes that are nothing to do with one another but share some aspect that they do not share a common ancestor then use an interface.  A good example of this is the IDisposable interface,  you use this when an object has some internal resource that needs to be explicitly cleaned up as soon as possible, so the interface has a single method called Dispose,  now you can apply this to any object since all objects will be different in how they dispose of their internal state, but you still want to be able to call objects as IDisposable types, hope that makes sence.

    An example of what I would do if I was you is shown below:

    using System;

    using System.Collections.Generic;

     

    namespace ConsoleApplication2

    {

        class Program

        {

            static void Main(string[] args)

            {

                Cleaner c = new Cleaner("bob", 5000);

                Manager m = new Manager("mike", 100000);

     

                Employee[] employees = new Employee[] { c, m };

                PrintEmployeeDetails(employees);

            }

     

            static void PrintEmployeeDetails(Employee[] employees)

            {

                foreach (Employee employee in employees)

                {

                    Console.WriteLine("Name=" + employee.Name + ", Salary=" + employee.Salary);

                }

            }

        }

     

        abstract class Employee

        {

            private string name;

            private int salary;

     

            protected Employee(string name, int salary)

            {

                this.name = name;

                this.salary = salary;

            }

     

            public string Name

            {

                get

                {

                    return this.name;

                }

            }

     

            public int Salary

            {

                get

                {

                    return this.salary;

                }

            }

        }

     

        class Manager : Employee

        {

            public Manager(string name, int salary)

                : base(name,salary)

            {

            }

        }

     

        class Cleaner : Employee

        {

            public Cleaner(string name, int salary)

                : base(name, salary)

            {

            }

        }

     

    }

     

     

    Mark.

  • Wednesday, January 17, 2007 7:22 PMIndian Ocean Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

    IMHO, here in your case, interface is not needed looking at your requirements. The abstract class serves best in the case.

    Why?

    - each employees will have their details like name, address, joining date, salary etc. These info is not specific to Manager or Cleaner but applicable to both
    - Now these details related implementation can be common and thats why it should go into Employees.

    Now when Interface required?

    - When you need to implement some method of same singature but with COMPLETELY DIFF IMPLEMENTATION for various classes then you should go for interfaces.
    - e.g. In this example, (just as example) lets say i have IEmployee interface having "string JobDetails()" method which returns "job description of specific type of employee" so Manager and Cleaner will have diff duties and that may be differ in implementation so we can implement this interface and provide diff impl details
    - Also, if some manager specific items is there then you can use IManager interface .. lets say having "Employees[] GetPersonWorkingUnderManager()" - this is only required in Manager but not in Cleaner

    Now another point of your question,
    If you want to know the details of an Employee after login then if you can have a method with common implementation under Employee (abstract class) which returns detail of an employee - doesnt matter which type of employee is there. Because this is applicable to both same way.
    So, If you have employee type specific thing then you should use interface - even in that case too, you dont need to go for interface, you can use abstract methods (just providing declaration of method and let derived class implement it their own)

    Also, Only one abstract class can be inherited in derived class so if you have multiple diff set of requirement then you should use diff interface for each type of set of requirements.

    Hope, it serves the purpose,

    If you have more questions or want more clarifications then please inform,

    HTH,

  • Wednesday, January 17, 2007 7:43 PMRizwanSharpMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    As Indian Ocean Said I also agree with him that you do not need the use of Interfaces here. Abstract classes will do the pretty job.

    And then when you need to check the type of the object that an Abstract class's object originally holds then the better choice is to use "as" keyword if you want to do processng on that type otherwise "is" will do the pretty god job.

    Here:

    Employee emp = new Programmer();

    Director dir = emp as Director; // It was not the case so it'll simply assing the dir a null reference

    if(dir == null) // it was not a Director's object

    {

    }

    else

    {

         // Yes it was

        int salary = dir.Salary;

    }

    Why prefer the use of as on is?

    because using is duplicates the parsing effort on CPU once you check type using "is" it'll try to parse and if successfull then returns true. Then seeing the true you use as object which will do the parsing again.

    So using as once ensures that you are not replicatng the work.

    I hope this will help.

    Best regards,

    Rizwan aka RizwanSharp

     

  • Wednesday, January 17, 2007 8:21 PMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks for reply Guys,
    I understand the concept of abstract classes better now. let me just explain what I am trying to do here.
    I have the abstract class employee with fname, lname, salary and PositionID and so on, all other classes inherit from this class "TeamLead, Manager, Supervisor, Maintenance, and Trainer"
    they all share the same properties fname,lnane and salary.
    all these users use the same login form.
    what I need to know is this. Is it possible to create an interface to tell me what kind of me what kind of employee logged in "manager, teamlead" so I can open the proper form for them and still use polymorphism?

    all employees access is based on their PositionID

    Thanks

  • Wednesday, January 17, 2007 8:31 PMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    RizwanSharp,
    I understand what you are saying but there is no way for me to know what kind of employee logged in before going into the database.
    Since the employee class is an abstract class I cant say
    Employee emp= new Employee()
    emp.authenticate();
    if(emp.PositionID==1) //Manager
    {
    frmManager managerForm= new frmManager();
    managerForm.Show();
    }
    thats why I was thinking of using an interface
  • Wednesday, January 17, 2007 8:38 PMIndian Ocean Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

     Sammy1971 wrote:

    all employees access is based on their PositionID

    So PositionID is defined for each specific employee type?

    I mean let say PositionID values for Manager has 1, TeamLead has 2, Supervisor has 3 etc?

    If so then you just use that to open specific form using switch case. So in this case as PositionID is part of Employee class, you dont need to worry which concrete class is there when you do this job,

    If i am wrong understanding PostionID but its just like "userid" then also you dont need any interface,

    as in previous post some has suggested, you can use something like;



    foreach(Employee emp in employees) {
        if(emp is Manager)
        {   ....    
            ManagerForm.Show();
            ....
        } else if (emp is TeamLead) {
            ...
        }
        :
        :
    }

     

    This should work fine,

    Or
    emp.GetType().ToString() will give you Fully qualified class name so you can use string comparison with that and will do the job,

    Also, I would like to add one more thing that Interfaces are for higher level abtraction and what you are looking for is opposite to that means you want to know the low level information about object type...

    HTH,

  • Wednesday, January 17, 2007 8:50 PMIndian Ocean Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

    You will need to open form after authenticating the person so when you are going to database for authentication, why you are not getting more information in Employee class after authentication

    I mean to say, lets you are calling some method from your login page to database for authentication and you are passing credentials to that method. So if its successfull authentication then get the PositionID at the same time and create the object you want based on PositionID and make the return type of that method as Employee so after authentication, the BLL class can return Employee object and you can do above job.

    I mean on <authenticationclass or simply common USER class object>.authenticate(userid, pass) it will fill up PositionID after successfull authentication and so you can use the rest of code you wrote to check PositionID as explained above.

    HTH,

  • Wednesday, January 17, 2007 9:04 PMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Indian Oceans,
    PositionID is stored at the database level and its a property in the abstract Class.
    In the login form, I am geeting the userid and password from the user
    txtuname, txtpassword, and send them to an sp to authenticate the user without using an objects
    This is the code for the login

    cmd.Connection = Config.objConn;
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "spLogin";
    cmd.Parameters.AddWithValue("?Uname" , this.txtUserName.Text);
    cmd.Parameters.AddWithValue("?Pass" , this.txtPassword.Text);
    using(SqlDataReader oDr=cmd.ExecuteReader(CommandBehavior.CloseConnection))

    if (oDr.Read())
    {
    Config.EmployeeNum = oDr.GetInt32(oDr.GetOrdinal("Employee_Number"));
    Config.accessLevel = oDr.GetInt32(oDr.GetOrdinal("PositionID"));
    Config.TeamID = oDr.GetInt32(oDr.GetOrdinal("TeamID"));
    Config.currentID = oDr.GetString(oDr.GetOrdinal("CorpID"));
    switch (Config.accessLevel)
    {
    case 1:
    frmMgr frmManager = new frmMgr();
    frmManager.Text += " " + oDr.GetString(oDr.GetOrdinal("First_Name")) + " ";
    frmManager.Text += oDr.GetString(oDr.GetOrdinal("Last_Name"));
    frmManager.MdiParent = this.MdiParent;
    frmManager.Show();
    this.Close();
    break;
    case 2:
    frmTr frmTrainer = new frmTr();
    frmTrainer.Text += " " + oDr.GetString(oDr.GetOrdinal("First_Name")) + " ";
    frmTrainer.Text += oDr.GetString(oDr.GetOrdinal("Last_Name"));
    frmTrainer.MdiParent = this.MdiParent;
    frmTrainer.Show();
    this.Close();
    break;
    case 3:
    frmTl frmTeamLead = new frmTl();
    frmTeamLead.Text += " " + oDr.GetString(oDr.GetOrdinal("First_Name")) + " ";
    frmTeamLead.Text += oDr.GetString(oDr.GetOrdinal("Last_Name"));
    MdiParent = this.MdiParent;
    frmTeamLead.Show();
    this.Close();
    break;
    default:
    frmAn frmAnalyst = new frmAn();
    frmAnalyst.Text += " " + oDr.GetString(oDr.GetOrdinal("First_Name")) + " ";
    frmAnalyst.Text += oDr.GetString(oDr.GetOrdinal("Last_Name"));

    frmAnalyst.MdiParent = this.MdiParent;
    frmAnalyst.Show();
    this.Close();

    break;
    }

    }
    else
    {
    MessageBox.Show("Invalid User Name or Password",Application.ProductName.ToString(),
    MessageBoxButtons.OK,MessageBoxIcon.Error);
    }

    Now I am using Config.accessLevel which is a public static variable to redirect the users to the proper form.
    I am thinking there has to be a better way to do this instead of using these static variables

    something like creating an authentication method in the Abstract Class or using an interface to do it.


  • Wednesday, January 17, 2007 9:09 PMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thats exactly what I was thinking of, I just cant think of a place to put the authentication method since I am using the abstract class , how can i get the information from the abstract employee class?
    see my code in my previous post

    thanks

  • Wednesday, January 17, 2007 9:22 PMIndian Ocean Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi, authentication method must not be in abstract class,

    See in my previous post,

    <authenticationclass or simply common USER class object>.authenticate(userid, pass)

    Authentication is a common code used by your presentation layer so it must be somewhere in Business login layer and that "BLL" object should be used by the presentation layer (Form) to authenticate the user. So till you call this method, no need to create Employee object but this authentication method should return the Employee class with filled in info

    HTH,

     

  • Wednesday, January 17, 2007 9:30 PMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    You mean as in a static class dependent of all objects?

  • Wednesday, January 17, 2007 9:44 PMIndian Ocean Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Not compulsion to have static class but you can create it.

    Or you can have,

    (Presentation layer)
    Your form method (on login button click or something like this use the following method to authenticate passing credentials,
    and use returned Employee class
       |
    (Business logic)
    AuthenticationClass
    Employee Authenticate(user, pass, other info if required);
       |
    (Database layer)
    real authentication mechanism which interacts with database, on success, it gets the detail of Employee, fill up Employee class and return back,

    Finally the flow, position of classes will be dependent on your application design but the concept is like this,

    I hope, now you will be clear what i am suggesting,

    HTH,

  • Wednesday, January 17, 2007 9:56 PMSammy1971 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    What you are suggesting is the exact same thing I want to implement. I am still having a problem figuring out how to implement it
    I just created a test app with these classes
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace AuthTest
        {
        abstract class Employee
            {
            private int id;
            private string name;
            public int ID
                {
                get
                    {
                    return this.id;
                    }
                set
                    {
                    this.id = value;
                    }
                }
            public string Name
                {
                get
                    {
                    return this.name;
                    }
                set
                    {
                    this.name = value;
                    }
                }
            public Employee ()
                {
                }
            public Employee (int id , string name)
                {
                }

            }
        }
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace AuthTest
    {
    class Manager:Employee
    {
    protected Manager ()
    : base()
    {
    }
    }
    }
    //Cleaner class
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace AuthTest
    {
    class Cleaner:Employee
    {
    protected Cleaner ()
    :base()
    {
    }
    }
    }

    //Manager class
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace AuthTest
    {
    class Manager:Employee
    {
    protected Manager ()
    : base()
    {
    }
    }
    }

    I created a static class and dropped a method to autheticate the users
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace AuthTest
    {
    static class Utilities
    {
    static public Employee Authenticate(string Uname, string Pass)
    {
    //How Can I impletent this and return an employee is my where I am having problems
    }
    }

    }
    in a login form I should call this method sending it the username and password
    Utilities.Authenticate("username","password");

    Do you see what I am getting at?

    Thanks

  • Thursday, January 18, 2007 7:52 AMIndian Ocean Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

    Hi,
    There are two solutions to do that easily, choose one of them whichever is comfortable,
    1. Make your abstract class of Employee to concrete class and make and extra interface like IEmployee
    - Concrete impl of common methods will go in Employee class while the abstract methods now will be part of interface so that way you can serve the abstract class purpose
    - Implement your Manager etc classes which inherits Employee and implements IEmployee
    - Employee class can have Authenticate method
    - As this is a concrete class; you can instantiate it and can use it easily
    - No need to implement Authenticate method in diff class as static method. this will do the job.


    2. In reference your last post, Employees and all the classes will be as it is and 
    In Utilities.Authentication(user, pass) method:

    Employee Authenticate(string username, string password)
    {

                SqlConnection conn = new SqlConnection();

                conn.ConnectionString = connstr;

                conn.Open();

                SqlCommand cmd = new SqlCommand();

                cmd.Connection = Config.objConn;

                cmd.CommandType = CommandType.StoredProcedure;

                cmd.CommandText = "spLogin";

                cmd.Parameters.AddWithValue("?Uname", username);

                cmd.Parameters.AddWithValue("?Pass", password);

     

                Employee emp = null;

     

                using (SqlDataReader oDr = cmd.ExecuteReader(CommandBehavior.CloseConnection))

     

                    if (oDr.Read())

                    {

                       

                        int iPositionID = oDr.GetInt32(oDr.GetOrdinal("PositionID"));

                        switch (iPositionID)

                        {

                            case 1: //Manager

                                emp = new Manager();

                                break;

                            case 2: //Cleaner

                                emp = new Cleaner();

                                break;

                            default:

                                break;

                        }

                        emp.FirstName = oDr.GetString(oDr.GetOrdinal("First_Name"));

                        emp.LastName = oDr.GetString(oDr.GetOrdinal("Last_Name"));
                        emp.PositionID = iPositionID); 

                        //Other properties you want to set

                    }

                }

                return emp;

     

            }

    So from your login action you call this method passing credentials and take the returned Employee object with you and then from the form you can check that what type of employee it is by using emp.PositionID or by (emp is Manager/Cleaner) like that. if emp is null then show msg to the user that credentials are not valid.

    Note: If want to use the first approach i have described then the authentication process code of second approach will go in Authenticate method in Employee class and it doesnt need to return Employee as it is a part of Employee itself so just fill in the parameters after authentication and then do the rest of the process.

    HTH,