Saturday, January 21, 2012

- Interfaces


An interface is only contain abstract member definitions which express a behavior that a given class or structure may choose to support (abstract methods are pure protocol which don't have any default implementation). A class or structure may support as many interfaces as necessary (multiple behavior).
Interface can be added through "Project -> Add New" Item as shown in below picture:

Add Interface to the project
Interfaces never specify a based class but they are allowed to specify base interface. Moreover interface members are implicitly public and abstract that's why they never specify access modifier. Interface can not have field, however it can define property.
Keep in mind that the direct based class must be the first item listed after the colon operator.As you can see in below picture .NET 4.0 provides a way to generate the properties and methods of an interface automatically:
using .NET 4.0 auto generation code features for interface
Explicit interface implementation  is useful when you have interfaces with identical members which helps you to resolve name clashes. Syntax:   returnType  InterfaceName.MethodName(params)
Explicitly implemented members are always implicitly private hence you need to use of explicit casting to access the member. Syntax  ((InterfaceName)ObjectName).MethodName

Enumerable Types:
Any type supporting a method named GetEnumerator()  belong to IEnumerable interfacecan be evaluated by the foreach construct. IEnumerable is as follow:

public interface IEnumerable
{
        IEnumerator GetEnumerator();
}

As you see GetEnumerator return IEnumerator Interface which provides the infrastructure to allow the caller to traverse the internal objects contained by IEnumerable-compatible container.

public interface IEnumerator
{
object Current { get; } //Get the current Item
       bool MoveNext();        //Move forward the internal position of the cursor.
       void Reset();           //Reset the cursor before the first member
}

Here is an Example to illustrate the IEnumerable and IEnumertor interfaces:

//now you may use foreach or use IEnumarator manually
class CustomColors:IEnumerable
{
    private Color[] allColors = new Color[10];

    public IEnumerator GetEnumerator()
    {
        return allColors.GetEnumerator();
    }
}

Alternatively, you may use yield keyword to build types what work with the foreach loop via iterators (iterator is a member that specifies how a container's internal items should be returned when processed by foreach. Just like below example:

class CustomColors:IEnumerable
{
    private Color[] allColors = new Color[10];

    public IEnumerator GetEnumerator()
    {
        foreach (Color c in allColors)
            yield return c;
    }
}

yield keyword is used to specify the value to be returned to the caller's foreach construct. When the yield return statement is reached,  the current location in the container is stored , and execution is restarted from this location the next time the iterator is called.
Named Iterator:  which allow you to return the IEnumerable interface, rather than the expected IEnumerator- compatible type. Take a look at below example:

class CustomColors:IEnumerable
{
    private Color[] allColors = new Color[10];

    public IEnumerable GetTheColor(bool reversed)
    {
        if (reversed)
            for (int i = allColors.Length; i != 0; i--)
                yield return allColors[i];
        else
            foreach (Color c in allColors)
                yield return c;
    }
}

And we can use it as follow:

static void Main(string[] args)
{
    CustomColors custom_colors = new CustomColors();
    foreach (Color c in custom_colors.GetTheColor(true))
        Console.WriteLine("Named Iterator");

Deep and Shallow Copy:
Deep copy:  result in brand new objects with identical state.
Shallow copy: point to the same object on the heap. (member by member)

ICloneable:
In order to give the ability to return an identical copy of itself to the caller, you should implement the ICloneable interface.

public interface ICloneable
{
    object Clone();
}

Clone method should copy the values of your member variables into a new object instance of the same type and return it to the user. As an example:

public object Clone()
{
    return new Shape(this.Name, this.Area);

If you type does not contain any internal reference type variables you can simply return the this.MemberwiseClone() otherwise you will need to create a new instance of any reference type variable during the cloning process.

IComparable:
This interface allows an object to specify its relationship between other like objects. Moreover you need to implement this interface if you wish to use .Sort method of array...

public interface IComparable
{
    int CompareTo(object obj);
}

For the sake of example let's implement the CompareTo method for Shape Type base on ShapeID to test the incoming object against the current instance :

public int CompareTo(object obj)
{
    Shape shape_temp = obj as Shape;
    if (shape_temp != null)
    {
        if (this.ShapeID > shape_temp.ShapeID)
            return 1;
        else if (this.ShapeID < shape_temp.ShapeID)
            return -1;
        else
            return 0;
    }
    else
        throw new ArgumentException("Parameter is not a Shape");
}

Alternatively you can implement the simpler for this case as follow:

public int CompareTo(object obj)
{
    Shape shape_temp = obj as Shape;
    if (shape_temp != null)
    {
        return this.ShapeID.CompareTo(shape_temp.ShapeID);
    }
    else
        throw new ArgumentException("Parameter is not a Shape");
}

As an example sort can be used as below:

Shape[] shapes =new Shape[5];
Array.Sort(shapes);

IComparer:
If you need to specify multiple sort orders you need to implement IComparer interface

public interface IComparer
{
    int Compare(object x, object y);
}

IComparer is usually not implemented on the type you are sorting, rather you implement this interface on any number of helper classes, one for each sort order.... Consider below example:

class ShapeNameComparer : IComparer
{
    public int Compare(object x, object y)
    {
        Shape shape1 = x as Shape;
        Shape shape2 = y as Shape;
        if (shape1 != null && shape2 != null)
            return string.Compare(shape1.Name, shape2.Name);
        else
            throw new ArgumentException("Parameter is not a shape");
    }
}

Now we can use the above helper class as follow:

Shape[] shapes =new Shape[5];
Array.Sort(shapes, new ShapeNameComparer());

Alternatively you can add following static read only property to have cleaner code:

public static IComparer SortByShapeName
{
    get { return (IComparer)new ShapeNameComparer(); }
}

And you may use it as follow:

Array.Sort(shapes, Shape.SortByShapeName);


Reference: Pro C# 2010 and the .NET 4 Platform by Andrew Troelsen.

No comments:

Post a Comment