Showing posts with label Object Oriented Development. Show all posts
Showing posts with label Object Oriented Development. Show all posts

Tuesday, March 20, 2012

Implementing IComparer Interface

We discussed IComparable interface in previous post and touched a bit on IComparer interface. IComparable interface only compares two objects of the same type and the class must implement IComparable interface. But what if you have two different objects that you want to compare, or what if you want to compare the same object, but the class doesn't implement ICmparable interface?

IComparer interface provides additional methods of comparing the objects. For example, we can sort a class based on multiple properties or fields.

This interface implements a method called "Compare()" which takes two object parameters and returns an integer value like "CompareTo()" method.

Let's use the same example like we used in previous post but this time we will use "IComparer" interface.

Order Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Orders
    {
        public int orderID { get; set; }
        public DateTime orderDate { get; set; }
        public int quantity { get; set; }
        public int customerID { get; set; }
        public string customerName { get; set; }
        public Status OrderStatus { get; set; }
           

    }
}

Three classes implementing "Compare" method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class OrderCompare:IComparer<Orders>
    {
        
        //you must implement Compare method declared in IComparable interface
        //sort in ascending order
        public int Compare(Orders order1, Orders order2)
        {
            if (order1.orderID > order2.orderID) return 1;
            else if (order1.orderID < order2.orderID) return -1;
            else return 0;
        }

    }
    class OrderCompare2:IComparer<Orders>
    {
        //but you can implement overloaded signature
        //sort in descending order
        public int Compare(Orders order1, Orders order2)
        {
            if (order1.orderID < order2.orderID) return 1;
            else if (order1.orderID > order2.orderID) return -1;
            else return 0;
        }
    }
    class OrderCompare3 : IComparer<Orders>
    {
        //sort by different field - string sort
        public int Compare(Orders order1, Orders order2)
        {
            return string.Compare(order1.customerName,order2.customerName);
        }
    }
}


Using the Sort Method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Program
    {
        
        static void Main(string[] args)
        {

            //Let's create a collection of orders and then sort them.
            List<Orders> orderlist = new List<Orders>
            {
                new Orders{orderID=100,orderDate=DateTime.Today,
                           quantity=5,customerID=10,
                           customerName="Second User",OrderStatus=Status.placed},
                new Orders{orderID=90,orderDate=DateTime.Today,
                           quantity=15,customerID=20,
                           customerName="First User",OrderStatus=Status.placed}
            };
            //let's not sort it
            foreach (Orders order in orderlist)
            { Console.WriteLine("Order ID:{0}", order.orderID); }

            Console.WriteLine(Environment.NewLine);

            //now sort using 1st comparer
            Console.WriteLine("Sort Using Order ID - Ascending");
            OrderCompare ordersort = new OrderCompare();
            orderlist.Sort(ordersort);
           foreach (Orders order in orderlist)
            { Console.WriteLine("Order ID:{0}, CustomerName{1} ", 
                                 order.orderID,order.customerName); }

           Console.WriteLine(Environment.NewLine);
           //now sort using end comparer
           Console.WriteLine("Sort Using Order ID - Descending");
           OrderCompare2 ordersort2 = new OrderCompare2();
           orderlist.Sort(ordersort2);
           foreach (Orders order in orderlist)
           { Console.WriteLine("Order ID:{0}, CustomerName{1} ", 
                                order.orderID, order.customerName); }

           Console.WriteLine(Environment.NewLine);
           //now sort using end comparer
           Console.WriteLine("Sort Using Customer Name");
           OrderCompare3 ordersort3 = new OrderCompare3();
           orderlist.Sort(ordersort3);
           foreach (Orders order in orderlist)
           { Console.WriteLine("Order ID:{0}, CustomerName{1} ", 
             order.orderID, order.customerName); }

            Console.Read();

        }
    }
}

Compare method allows you to compare two objects even if they don't implement IComparer interface. You simply pass an instance of the class implementing this interface to the Sort method.

Thank you.

Saturday, March 17, 2012

Implementing IComparable Interface

As we discussed in previous posts, an interface is a contract. A class implementing an interface must implement all the signatures that are declared in this interface.

Why do you need interfaces if all they provide are the method signatures with no actual implementation? One of the reason you implement an interface is to ensure code reuse and standards. By implementing an interface, you can be virtually guaranteed that a class implementing an interface must have implemented its signatures.

For example, suppose you have a car class and a truck class, both implementing an interface IAutoMobile. IAutoMobile has a signature method called "Horsepower". Since both car and truck classes implement IAutomobile, you can be sure both classes will also implement "Horsepower" method.You can write a static method that can accept an object of type IAutoMobile and call the "Horsepower" method. Depending on the object type you passed to this method (class or truck), the code will execute the appropriate "Horsepower" and return you the information.

To see an example of this, see my previous post titled Abstraction via Interfaces - II.

While you can create and implement your own interfaces, .NET provides several interfaces that you can implement  in your classes. Today, we will discuss one such interface "IComparable".

IComparable interface provides a "CompareTo" signature that you can implement in a class to compare the two objects of this type.

Let's consider an example...

Orders Class implementing IComparable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Orders : IComparable
    {
        public int orderID { get; set; }
        public DateTime orderDate { get; set; }
        public int quantity { get; set; }
        public int customerID { get; set; }
        public Status OrderStatus { get; set; }

        //you must implement CompareTo method declared in IComparable interface

        public int CompareTo(object obj)
        {
            //cast the object to its proper type
            Orders order = obj as Orders;
            //OR
            //Orders order = (Orders)obj;
            
            if (this.orderID > order.orderID) return 1;
            else if (this.orderID < order.orderID) return -1;
            else return 0;
        }
        
    }
}


Main Method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Program
    {
        static void Main(string[] args)
        {

            //Let's create a collection of orders and then sort them.
            List<Orders> orderlist = new List<Orders>
            {
                new Orders{orderID=100,orderDate=DateTime.Today,quantity=5,
                           customerID=10,OrderStatus=Status.placed},
                new Orders{orderID=90,orderDate=DateTime.Today,quantity=15,
                           customerID=20,OrderStatus=Status.placed}
            };
            //let's not sort it
            foreach (Orders order in orderlist)
            { Console.WriteLine("Order ID:{0}", order.orderID); }

            Console.WriteLine(Environment.NewLine);
            //now sort it
            orderlist.Sort();
            foreach (Orders order in orderlist)
            { Console.WriteLine("Order ID:{0}", order.orderID); }

            Console.Read();

         }
    }
}

Let's review the output before and after the sort. If you look closely, the output before orderlist.Sort() method is in the order objects were added to the collection, but after the Sort(), the objects are listed in ascending order based on the order ID. You may be wondering how come we didn't call the CompareTo method? Actually a Sort() method internally uses CompareTo method to compare the objects based on your implementation. Try the same example but without implementing IComparable interface and you will receive an error.

Output



The CompareTo method in the above example takes a generic object which then must be cast into a specific type. Framework provides another type safe interface "IComparable<>" which you can implement in your classes and no typecasting will be necessary.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ComparableInterface
{
    class Orders2 : IComparable<Orders2>
    {
        public int orderID { get; set; }
        public DateTime orderDate { get; set; }
        public int quantity { get; set; }
        public int customerID { get; set; }
        public Status OrderStatus { get; set; }

        //you must implement CompareTo method declared in IComparable interface

        public int CompareTo(Orders2 order)
        {
            //not casting necessary

            if (this.orderID > order.orderID) return 1;
            else if (this.orderID < order.orderID) return -1;
            else return 0;
        }
    }
}


IComparable is useful when a class implements this interface and you are comparing the same objects. CompareTo method takes another object which is of the same type and compares the current object to the passed one. But what if your class doesn't implement IComparable or if you want to compare two different objects. Framework provides another interface called IComparer. This interface defines a Compare() method that can take two objects of another type and compares them. We will look at an example of the ICompare interface in future post.

Thank you.

Sunday, March 4, 2012

Events in C#

An event allows an object to broadcast a notification that may be of value to other objects listening to this event.

Consider you have a class (caller) monitoring stock market changes (callee). This class calls a method within another class which subscribes to an external service to periodically receive price updates.

One way to implement this would be to have a timer in the caller class which periodically fires, calling the method in the callee class, which then returns the stock prices.

A more elegant solution would be to have the callee fire an event when price changes and caller class to listen to those events. As soon as callee fires an event, caller will get notification and update the stock prices.

Events are useful for one class to broadcast a notification and all client objects listening to these events can do something with it. Events are created and used by using delegates. Review my previous post about delegates to get a better understanding about delegates and their purpose. Delegates are basically wrappers around a method allowing these methods to be called via delegates.

Let's use the above example to see how you can hook up events to get the stock price changes.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{
    //create a delegate
    public delegate void ChangeStockPrice(object sender, EventArgs e);
    
    public class GetStockPrices
    {
         public string _ticker;
         public double _price;

         
         //create an event
         public event ChangeStockPrice PriceUpdated;

        //when ever price changes, raise the PriceUpdated event;
        protected virtual void OnPriceChange(EventArgs e)
           {
                  if (PriceUpdated !=null)
                  PriceUpdated(this, e);
           }

       //create a method to change stock price
        public void ChangePrice(string ticker,double price)
           {
                _ticker=ticker;
                _price = price;
                // fire the event
                OnPriceChange(EventArgs.Empty);
            }
       }
    //create an event listener class
    public class EventListener
   {
     private GetStockPrices stockprice;
     //attach event
    public void Attach(GetStockPrices stock)
     {
         stockprice=stock;
         stockprice.PriceUpdated += new ChangeStockPrice(PriceChanged);
     }
     protected void PriceChanged(object sender, EventArgs e)
    {
        Console.WriteLine("Ticker: {0}, Price: {1}", stockprice._ticker, stockprice._price);
    }
    //you can detach an event
    public void Detatch()
    {
        stockprice.PriceUpdated -= new ChangeStockPrice(PriceChanged);
    }
   }

}

Now let's call the above class which will fire an event showing up the stock price information.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
                   
        static void Main(string[] args)
        {
            
           GetStockPrices stockprice= new GetStockPrices();
            EventListener Listener = new EventListener();
            Listener.Attach( stockprice );
            stockprice.ChangePrice("MSFT",33.50);
            //detatch
            Listener.Detatch();
            Console.Read();
      }
    }
}


Events allow multiple subscribers to subscribe to an event fired by one class, instead of trying to poll the class to see if something change. When you are running multi-threaded applications, the parent thread can fire off another thread and then listen to the object on child thread raising the event once the processing is complete.

Hope this helps in understanding events and how you can use them in your application.

Thank you.

Monday, February 20, 2012

Reflection in .NET

Reflection is the process of discovering classes, modules, assemblies or the type information of an object at run-time. Reflection works by extracting metadata information from an assembly and using this metadata to do something with it. System.Reflection namespace in .NET Framework provides the classes and interfaces that you can use to discover a class, instantiate it, discover its methods, properties and invoke them at run-time just like you would during compile time.


There are many uses of reflection, but let's demonstrate one potential use with an example.


Suppose for example, you have a sales application installed on sales associates laptops. This application allows sales associates to enter sales orders on their laptops, when they visit the clients. The application is run in offline mode but when the sales associate returns back to the office and connects to the network, the application will detect it and automatically uploads the sales orders in a centrally hosted database.


When a sales associate enters the information, a collection of the Orders object is serialized on sales associates laptop. When this laptop is connected to the company network, the application deserializes the Orders, uses reflection to type cast the object into the Orders Type and then calls the appropriate methods to save data in the database.


Let's illustrate this with an example.

//Create an Orders Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ReflectionTest    
{
public class Orders
{
      private int _itemNumber;      
      private int _quantity;      
      private int _customerNumber;
      //properties
     
      public int ItemNumber
      { 
        get { return _itemNumber; }          
        set { _itemNumber = value; }      
      }
      public int Quantity          
      {
         get { return _quantity; }         
         set { _quantity = value; }      
      }
      public int CustomerNumber         
      {
         get { return _customerNumber; }         
         set { _customerNumber = value; }        
      }
      //constructor
     
      public Orders() 
      {}
     //Method to save data to the database
     
public void SaveToDB(List<Orders> orders)           
     {
       // do something here         
     }
  }
}

 Since we are going to serialize this object and save it on associate's laptop, let's write a class that is serializable and has a variable which stores the collection of Orders object (you can make it generic to allow for serializing and storing any object).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace  ReflectionTest 
{
    [
Serializable]    

    public class SaveObjectLocally    
    {
     //use generics so this class can be used to store any object types not just Orders
    private List<Orders> _collObjects = new List<Orders>();     

    private string _saveMethod;     
    private string _className;
    public SaveObjectLocally() { }     
    //properties
     public List<Orders> ObjectList
     {          
         get { return _collObjects; } 
         set { _collObjects = value; }     
     }
     public string SaveToDB
     {          
         get { return _saveMethod; }          
         set { _saveMethod = value; }     
     }
     public string ClassName          
     {
         get { return _className; }          
         set { _className = value; }     
     }
     //serialize
     public void Serialize(string filePath)
     {
         
Stream stream = File.Open(filePath, FileMode.Create);           

          BinaryFormatter bf = new BinaryFormatter();
          bf.Serialize(stream, this);
          stream.Close();     
     }
    //deserialize
      public SaveObjectLocally DeSerialize(string filePath)         
     {
        Stream stream = File.Open(filePath, FileMode.Open);         
        BinaryFormatter bf = new BinaryFormatter();         
        SaveObjectLocally SaveObject = (SaveObjectLocally)bf.Deserialize(stream);
        stream.Close();  
        return SaveObject; 
          }
 
    }
}

//Main Program

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace  ReflectionTest 
{
    class Program 

    {
        
static void Main(string[] args) 
         {
              
Orders clientOrder = new Orders();
              clientOrder.ItemNumber=123;
              clientOrder.Quantity = 5;
              clientOrder.CustomerNumber=101;
              //lets assign this order to SaveObjectLocally and 

              //then save it on local machine           
             //create a list object
             
List<Orders> ordersList= new List<Orders>();
             ordersList.Add(clientOrder);
             SaveObjectLocally save = new SaveObjectLocally(); 
             save.SaveToDB = 
"SaveToDB"; 
             save.ObjectList = ordersList;


             //serialize

             save.Serialize(@"C:\Temp\Orders.xml");
                
           }
         //deserialize the saved object and upload.
         public static void UploadData() 
          {

          SaveObjectLocally save = new SaveObjectLocally(); 
          SaveObjectLocally retrieveObject = save.DeSerialize(@"C:\Temp\Orders.xml"); 
          string saveMethod = retrieveObject.SaveToDB;
          string className = retrieveObject.ClassName; 
          List<Orders> orders = retrieveObject.ObjectList;
          //now use reflection to instantiate the object
          Type ClassType = Type.GetType(className);          
          object obj = Activator.CreateInstance(ClassType);
          System.Reflection.MethodInfo callingMethod = ClassType.GetMethod(saveMethod);
          callingMethod.Invoke(obj,new Object[] {orders});
         }
         //If you have multiple objects serialized 

        //you can loop through all the files and upload one by one.
   }  
}

The example above is one use of Reflection where you can instantiate an object at run time and invoke its methods.

GetType.GetMethod and GetType.GetMethods() return you a single method or a list of methods.

Similarly, GetType.GetField() and GetType.GetFields() return you a single field or an array of all fields.

GetType.GetProperty() and GetType.GetProperties() returns property or a list of properties respectively.

You can also find out the parameters a method needs and also its return type. MethodInfo() provides information about the return type of a method and GetParameters() provides information about the parameters that a method expects.

GetConstructors() returns a list of constructors associated with this class.

Assembly Class
Assembly class is used to gather information about an assembly and manipulate the assembly. You can use it to load modules and assemblies at runtime and also search the type information within an assembly once it is loaded. Assembly class has the following methods


  • Load() - You can pass the assembly name as input parameter to search and load the assembly.
  • LoadFrom() - Takes the complete path of an assembly to search at a particular location.
  • GetExecutingAssembly() - Get the information about the currently running assembly.
  • GetTypes() - Allows you to obtain the details of all the types that are present in the assembly.
  • GetCustomAttributes() - Gets the list of custom attributes associated with this assembly. You can also pass a Type Object as a second parameter to this method to find the attributes of a specific type associated with this assembly.

As you can imagine, reflection is a very powerful feature that allows for late binding and flexibility otherwise not available during compile time. Hopefully this article will provide you enough pointers to try out reflection on your own and discover some of its additional powerful features.

Thank you and as always, your comments are welcome.

          

Friday, February 17, 2012

Generics in .NET Framework

If you came from C++ and worked on a VB 6.0 application, one thing that stood out like a sore thumb was the lack of templates. Templates in C++ allowed for type-safety and code re-usability. In VB 6.0 and in earlier versions of .NET Framework (1.0 and 1.1), you did something like this

Public Sub Add(ByVal param1 As Object, ByVal param2 As Object)

      If TypeOf(param1) = GetType(String) AND TypeOf(param2) = GetType(string) Then

              console.writeline("String=" & param1.ToString & param2.ToString)

      Else If TypeOf(param1) = GetType(int) AND TypeOf(param2) = GetType(int) Then

             console.writeline("Integer=" & DirectCast(param1,int) + DirectCast(param2,int)

      End If

End Sub

Note - C# also suffered from same limitation in 1.0 and 1.1

Aside from all the typecasting, there is something else going on here. Recall from my previous post about boxing and unboxing. If you passed integer values to this method, the passed values will be boxed and then DirectCast will unbox these values since integer is a value type.

Although this provided you flexibility in the sense that you didn't have to write two separate methods - one for numeric operation and one for string operation, it came at a performance cost.

Even if you avoided methods like these, using an arraylist with value types will result in boxing/unboxing as well (recall an example in previous post).

.NET 2.0 introduced the concept of generics. Generics allow you to define a type-safe method, class or structure without committing to a specific data type. You can write code that is just as flexible as the above example, promotes code re-use without the performance degradation of boxing / unboxing.

 Lets consider an example. Assume you want to use the flexibility of an arraylist but without its drawbacks, you can create a generic list object that framework will convert to a passed data-type during compile time.


List<int> Test = new List<int>();     //a list of type int
Test.Add(1);     //no boxing
Test.Add(2);
Test.Add("A");    //compile time error - type safe


Generic Method



void Add<T>(ref T param1)
       {
           T results;
           results = param1;
           Console.WriteLine(results);
       }


You can also declare a generic class or a structure.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace GenericTest
{
    class GenericList<T>
    {
        void AddToList(T input) { }
    }
}



//Test Generic Class

GenericList<int> list1 = new GenericList<int>(); // list of type int
GenericList<string> list2 = new GenericList<string>(); // list of type string


As I previously mentioned, Generics allow for code re-use without compromising performance. Generics was perhaps one of the most powerful enhancement in .NET Framework 2.0.

As always, your comments are welcome.



Monday, February 13, 2012

Difference between an Interface and an Abstract class

All Programming Fundamentals! It is rather easy to articulate the difference between the two, but I have seen people stumble when asked to explain it. So today, we will try to cover this topic and provide an example to clarify some of the key differences.

 Abstract Class
An Abstract Class is just like any other class with a few key differences. As we discussed in my previous post, non-static classes can be instantiated except with one type of class - an Abstract Class. In other words, an abstract class is one that cannot be instantiated and can only be used as a parent class in other derived (concrete) classes. Since this class cannot be instantiated and you cannot use a non-static class without instantiating it, you cannot use the abstract class by itself. You must inherit from it in other class(es) to use it.

An abstract class may have one or more methods that are completely implemented but it must have at least one abstract method that must be implemented in the derived class(es). This is what makes the abstract class - abstract.

So, in a nutshell an abstract class is just like any other class except that it cannot be instantiated and must have one or more abstract (unimplemented) methods.

Interface
An Interface is not a class. It is a contract and all classes that implement the interface must implement all the properties/methods declared in an Interface.

Unlike an abstract class, an interface cannot have actual implementation of any property/method and also all the properties / methods must be declared public.

Since an interface cannot have any implementation, all the classes inheriting this interface must implement all the methods defined in the interface. Abstract class on the other hand can have fully implemented methods and derived classes can simply use that implementation.

If an abstract class has all the methods defined as abstracts, then both Interface and Abstract class is the same.

Why would you use one over the other?

Both interfaces and abstract classes are good if you want to keep the same structure in your classes inheriting from it. But abstract class allows you to implement one or more common method that can be used as is by all the classes. One advantage that interface have over abstract class is that at least in C# and VB.NET (also true in Java but not in C++) a class can only inherit from one class, while it can implement multiple interfaces.

Interfaces are generally used to define the abilities of a class i.e. what a class can do. For example - IComparable interface. This interface defines "Compare To" signature which can be implemented in the class to compare the instance of an object with another object of the same type. Any class that implements IComparable interface must be capable of doing so.

Abstract classes on the other hand generally implement or define the core capability of the class. For example a MemoryStream class can inherit from a Stream abstract class that implements a Serialize method to serialize the content.

You generally want to use interface if various classes only share certain features, although they may be of different type. For example, a class called Car and a class called Plane may implement the same IMovable interface. You want to use an abstract class when both classes are of same or similar kind. For example a class "BMW" and a class "Lexus" can inherit from the same abstract class called "Car".

If you modify an interface and add a new method, you must modify all the classes implementing that interface to implement that method. You can however modify an abstract class and as long as you fully implement a new method, you don't have to touch other classes inheriting from it.

Let's see both Interface and Abstract class in action.

Abstract Class

Using System;
namespace AbstractInterface
{
    public abstract class Student  
           // notice keyword abstract. In VB.NET the equivalent keyword is MustInherit
     { 
        protected string studentnum;     //protected variables
        protected string studentname;


      public abstract String StudentNumber 
              // notice the keyword abstract. The property is not fully implemented.
           {
             get;
             set;
           }
      public abstract String StudentName
        {
           get;
           set;
        }
     public String GetStudentInfo() // notice this method is fully implemented
      {
        return "Student Number: " + studentnum + " Name: " + studentname;
      }
     public abstract String EnrollmentStatus(); // notice this method is not implemented.


    }
}
   
Concrete Class


using system;
namespace AbstractInterface
{
    public class GraduateStudent : Student // this class inherits from Student class.
   {
     public GraduateStudent()   //constructor
      {
       }
      public override String StudentNumber
           // remember abstract class didn't implement this property so we have to implement it here.
           //   Notice keyword override
        {
           get
            {
               return studentnum;
            }
            set
            {
               studentnum = value;
            }
        }
        public override String StudentName
         
        {
           get
            {
               return studentname;
            }
            set
            {
               studentname = value;
            }
        }


      public new String GetStudentInfo() // this method is implemented in base class.
      {
        return base.GetStudentInfo();
      }


    }
    public override String  EnrollmentStatus () // notice this method is not implemented in base class


      {
        return studentname + " is enrolled."
      }


    }
}

Now lets see an Interface Example

Interface


Public interface IStudent // As a convention, interfaces are prefixed with "I"
{


 String StudentNumber
              // No need to specific "public" since interface can only have public properties/methods.
           {
             get;
             set;
           }
      String StudentName
        {
           get;
           set;
        }
     String GetStudentInfo();
     
     String EnrollmentStatus();
   
          // notice no implementation of any method or property
   }

Concrete Class using Interface


using system;
namespace AbstractInterface
{
     public class Student2 : IStudent    // implements interface


      protected string studentnum;     //protected variables
      protected string studentname;


     public  Student2  ()   //constructor
        {
        }
      public String StudentNumber
           // must be implemented here, otherwise compiler will throw error.
         
        {
           get
            {
               return studentnum;
            }
            set
            {
               studentnum = value;
            }
        }
        public String StudentName
       
        {
           get
            {
               return studentname;
            }
            set
            {
               studentname = value;
            }
        }


      public String GetStudentInfo() // implemented here
      {
        return "Student Number: " + studentnum + " Name: " + studentname;
      }


    }
    public String  EnrollmentStatus ()


      {
        return studentname + " is enrolled."
      }


   // notice - all properties and methods declared in interface must be implemented. Every class inheriting       //from this interface must implement all of them.


    }


}

Hopefully this will help clarify some of the differences between an Interface and an Abstract class. As always, your comments are welcome.