Interfaces

.Interfaces
Interface Declaration | Interface Implementation | Interface Characteristics | Built-in Interfaces | Interface vs Abstract Classes | Interfaces vs Delegates | Simple Custom Interface | Interface with Extension Method | Refactored with Additional ICatcher<T> Generic Interface

An interface is declared as a reference type which contains a group of abstract members used to model certain behaviors. An interface represents a contract where the implementing class or struct must define the entire group of abstract members. The capability of interfaces are important in languages that do not support multiple inheritance from classes (e.g. C#, Java). Interfaces are also used to simulate inheritance for structs, as structs do not support inheritance.

An interface represents a contract through which a class or struct guarantees that it will implement certain methods, provide certain properties and indexers, and support certain events, all of which are specified in the interface definition. An interface definition contains only the declarations (no implementation logic) for a set of behaviors that a class or a struct can choose to support. By using interfaces, behavior from multiple sources can be included in a class or struct. This ability to reuse the declarations of behaviors is important in C# because the language does not support inheritance from more than one class.

Using interfaces creates standard behaviors and standard names for the methods implementing the behavior. This standardization of behaviors provided by interfaces allows you to understand a good deal about a class simply by looking at the interfaces it implements. The .NET framework contains many built-in interfaces that are widely used. Additionally it is common for programmers to create custom interfaces.


Interface Declaration

  • Interface declarations contain only the signatures (no implementation code) of their members. Interface members can be methods, properties, events or indexers. That is, an interface can not contain constants, fields, operators, instance constructors, destructors, or types.

  • An interface declaration appears similar to a class declaration. Except an interface is defined using the keyword interface, and by convention the name of interfaces are prefixed with an "I".

  • Interfaces can not be declared as static. Interfaces are a form of polymorphism, and polymorphism works through instances.

  • The interface members are not allowed to have any access modifiers. Interface members always default to public access.

  • An interface can be declared as a member of a namespace or a class.
    • No element defined directly in a namespace can be explicitly declared with an access modifier of: private, protected, or protected internal. So interfaces declared directly within a namespace can only be declared as either public or internal, and just like classes and structs defined in a namespace, they default to internal access.

    • However, interfaces declared inside classes can have any of the access modifiers (public, private, protected, internal, protected internal) and default to private access.
  • Interface Extension Methods are a way of associating actual code with interface definitions. However extension methods should be used with caution.

  • You can extend an interface to add new methods or members. In the new interface definition, use the colon operator followed by the name of the original interface. This is very similar to derivation in classes.
Top



Interface Implementation

  • When the class or struct implements the interface, they provide the code to implement all the members declared by the interface.

  • An interface can't be instantiated directly. Its members are implemented by any class or struct that implements the interface.

  • To implement an interface on a class, you use the colon operator, followed by the name of the interface, similar to the syntax for inheritance.

  • Classes can derive from no more than one class, but can implement any number of interfaces. If a class has a base class and one or more interfaces, the base class must be listed first, followed by the interface names separated by commas.

  • A class that implements an interface may mark any of the interface methods as virtual. These methods may then be overridden by derived classes.

  • If a base class implements an interface, any class that's derived from the base class inherits that implementation.

  • Interfaces can be extended. The extended interface subsumes the original interface, so any class that implements the extended interface must also implement the original interface as well.

  • If a class implements two or more interfaces containing methods which have the same name, you resolve the conflict by prefixing the method name with the name of the interface and the dot operator. (Same syntax as calling a static method).

  • interfaces can be implemented either implicitly or explicitily:
    • Implicitly - access the interface methods and properties as if they were part of the class. (The most common approach).

    • Explicitily -access the interface methods and properties through the interface. Can be used to disambiguate class and interface methods that would otherwise conflict. Can also be used to hide the details of an interface.

Implicit vs Explicit Interface Implementation

namespace ExplicitInterface
{
    public interface I1
    { void InterfaceMethod(); }

    public interface I2
    { void InterfaceMethod(); }

    class TheClass : I1, I2
    {
        // Implicit Implementation
        public void InterfaceMethod()
        { System.Console.WriteLine("Implicit"); }

        // Explicit Implementation
        void I2.InterfaceMethod()
        { System.Console.WriteLine("Explicit"); }
    }

    class Program
    {
        static void Main()
        {
           TheClass MyClass = new TheClass();
           I2 i2 = (I2)MyClass;

           MyClass.InterfaceMethod();   // Implicit Call
           i2.InterfaceMethod();        // Explicit Call
        }
    }
}

Top



Interface Characteristics

  • Properties and indexers of a class can define additional accessors for a property or indexer that's defined in an interface. For example, an interface might declare a property that has a get accessor. The class that implements the interface can declare the same property with both a get and set accessor.

  • You can use the is operator to determine whether an object derives from a base class or implements an interface. The is operator returns a value indicating if the cast is valid, however it does not perform the cast.

  • The as operator attempts to cast a class or an interface, and returns null if the cast is not valid.

Top



Built-in Interfaces

The .NET base class library contains hundreds of predefined interface types that are implemented in various classes and structures. Some of the predefined interfaces are commonly used when creating custom types. For example if you create a class of Cars and you want to be able to compare their gas mileage ratings. To test if two Cars have the same gas mileage rating, you could implement the IEquatable interface and use its Equals() method for testing equality. To create an ordered list of the Cars according their gas mileage, you could implement the IComparer interface and use its Compare() method to order the collection of cars (Use IComparable for default sort order and IComparer of secondary sort orders). Later you may use the same interfaces when you create a class of Computers and want the same behavior of testing for equality and order. Using the predefined interfaces creates standard behaviors and standard names for the methods implementing the behavior. This standardization of behaviors provided by interfaces allows you to understand a good deal about a class simply by looking at the interfaces it implements. Below are a few of the commonly used predefined interfaces and the methods associated with their behaviors.



ICloneable

ICloneable - requires that your implementation of the Clone method return a copy of the current object instance. It is recommend that ICloneable not be implemented in public APIs. Methods:

  1. Clone - Creates a new object that is a copy of the current instance.



IConvertible

IConvertible - convert the value of an instance of an implementing type to a common language runtime type that has an equivalent value.

  1. ToBoolean - Converts the value of this instance to an equivalent Boolean value using the specified culture-specific formatting information.
  2. ToByte - Converts the value of this instance to an equivalent 8-bit unsigned integer using the specified culture-specific formatting information.
  3. ToDouble - Converts the value of this instance to an equivalent double-precision floating-point number using the specified culture-specific formatting information..
  4. ToString - Converts the value of this instance to an equivalent String using the specified culture-specific formatting information.
  5. Several more methods, See IConvertible documentation.



ICollection<T>

ICollection<T> - methods and properties for generic collections.

  1. Add - Adds an item to the collection.
  2. Clear - Removes all items from the collection.
  3. Contains - Determines whether the collection contains a specific value.
  4. GetEnumerator - Returns an enumerator that iterates through the collection.
  5. Several more methods, See ICollection<T> documentation.



IComparable and IComparer

IComparable<T>
IComparable<T> - establishes the default sort order. Implement Method:
  1. CompareTo - Compares the current object with another object of the same type.
IComparer<T>
IComparer<T> - establishes secondary sort order(s). Implement Method:
  1. Compare - Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.



IComparable (default sort order) and IComparer (secondary default orders)

using System;
using System.Collections.Generic;

namespace ComparableExample
{

    class Car : IComparable<Car>
    {
        public string Make { get; set; }
        public string Model { get; set; }
        public double GasMileage { get; set; }

        // Cause Default Sort to be by Make
        public int CompareTo(Car compareCar)
        {
            if (compareCar == null)
                return 1;
            else
                return this.Make.CompareTo(compareCar.Make);
        }

        // Override ToString Method
        public override string ToString()
        {
            return String.Format("Make: {0}, Model: {1}, Gas Mileage: {2}", this.Make, this.Model, this.GasMileage);
            }
    }

    class Car_SortByGasMileageDescending : IComparer<Car>
    {
        public int Compare(Car x, Car y)
        {
            if (x.GasMileage < y.GasMileage)
                return 1;
            else if (x.GasMileage > y.GasMileage)
                return -1;
            else
                return 0;
        }
    }

    class Program
    {
        static void Main()
        {
            List<Car> myCars = new List<Car>
            {
                new Car() {Make = "Ford", Model = "Taurus", GasMileage = 25},
                new Car() {Make = "Chevy", Model = "Prism", GasMileage = 40},
                new Car() {Make = "Buick", Model = "LeSabre", GasMileage = 28}               
            };

            // Before Sort
            Console.WriteLine("Before Sort");
            foreach (Car theCar in myCars)
                Console.WriteLine(theCar.ToString());

            myCars.Sort();

            // After Default Sort
            Console.WriteLine("\nAfter Default Sort (IComparable)");
            foreach (Car theCar in myCars)
                System.Console.WriteLine(theCar.ToString());

            // After Gas Mileage Descending Sort
            Car_SortByGasMileageDescending gasDescending =
                new Car_SortByGasMileageDescending();
            myCars.Sort(gasDescending);

            Console.WriteLine("\nAfter Gas Mileage Sort (IComparer)");
            foreach (Car theCar in myCars)
                System.Console.WriteLine(theCar.ToString());
        }
    }
}



IDbConnection

IDbConnection - represents an open connection to a data source, and is implemented by .NET Framework data providers that access relational databases.

  1. Open - Opens a database connection with the settings specified by the ConnectionString property of the provider-specific Connection object.
  2. Close - Closes the connection to the database.
  3. BeginTransaction - Begins a database transaction.
  4. Several more methods, See IDbConnection documentation.



IDisposable

IDisposable - Defines a method to release allocated resources.

  1. Dispose - Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.



IEnumerable<T>

IEnumerable<T> - Exposes the enumerator, which supports a simple iteration (i.e. using foreach) over a collection of a specified type.

  1. GetEnumerator - Returns an enumerator that iterates through the collection.



IEnumerator<T>

IEnumerator<T> - Supports a simple iteration over a generic collection. /p>

  1. Inherits Dispose (IDisposable>, MoveNext (IEnumerator), and Reset (IEnumerator).



IEquatable<T>

IEquatable<T> - Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.

  1. Equals - Indicates whether the current object is equal to another object of the same type.



IEqualityComparer<T>

IEqualityComparer<T> - Defines methods to support the comparison of objects for equality.

  1. Equals - Determines whether the specified objects are equal.
  2. GetHashCode - Returns a hash code for the specified object. Hash codes are intended for efficient insertion and lookup in collections that are based on a hash table. Hash functions are usually specific to each type and, for uniqueness, must use at least one of the instance fields as input. Hash codes should not be computed by using the values of static fields.

Top



Interface vs Abstract Classes

An interface is similar to an abstract class in that they can not be instantiated. However the differences between an abstract class and an interface are:

  1. The members of an abstract class can either be partially implemented or not implemented at all. The members of an interface are always not implemented at all.
  2. An interface can not have access modifiers for its members as all interface members are assumed public. An abstract class can contain access modifiers for its members (default is private).
  3. A class can implement an unlimited number of interfaces, but may inherit only one abstract class.
  4. An interface should be used when you want to describe "what it does", but you do not care "how it does it". If you do care "how it does it" or care about "how parts of it are done", then you should use an abstract class.

If you have only one function with a signature only, then a couple of issues should be addressed before deciding to implement it as an abstract class or an interface:

  1. If you implement it as an abstract class you may preventing derived classes from inheriting from any other classes (as a class can only inherit from one class, but can implement from any number of interfaces).
  2. If the function needs an additional member in the future, if it is implemented as an interface then all implementations will need to be found and updated with the new member. If is implemented as an abstract class, they you can provide a default for the additional member which might prevent having to find and change all the derived members.
Top



Interfaces vs Delegates

Delegates and interfaces are similar in that they enable the separation of specification and implementation. Multiple independent authors can produce implementations that are compatible with an interface specification. Similarly, a delegate specifies the signature of a method, and authors can write methods that are compatible with the delegate specification. When should you use interfaces, and when should you use delegates?

Delegates are useful when:

  • A single method is being called.
  • A class may want to have multiple implementations of the method specification.
  • It is desirable to allow using a static method to implement the specification.
  • An event-like design pattern is desired (for more information, see the Events Tutorial).
  • The caller has no need to know or obtain the object that the method is defined on.
  • The provider of the implementation wants to "hand out" the implementation of the specification to only a few select components.
  • Easy composition is desired.

Interfaces are useful when:

  • The specification defines a set of related methods that will be called.
  • A class typically implements the specification only once.
  • The caller of the interface wants to cast to or from the interface type to obtain other interfaces or classes.




Top



Simple Custom Interface

.Implements Two Interfaces


Simple Custom Interface - Program Output

This program declares two interfaces which are implemented in the Dog and Cat classes. The Dog and Cat classes are derived from the Animal class.

using System;
namespace DrDolittle
{
    // Noise Interface
    public interface INoise
    {
        void HappyNoise();
        void AngryNoise(int noiseLevel);
    }

    // Reaction Interface
    public interface IReaction
    {
        void HappyReaction();
        void AngryReaction();
    }
   
    // Base Animal Class
    public class Animal
    {
        public string Name { get; set; }
        public int Mood { get; set; }
        public Animal() { Name = ""; Mood = 0; }
    }

    // Dog - inherits from Animal and implements INoise and IReaction
    public class Dog : Animal, INoise, IReaction
    {
        public void HappyNoise()
        {
            Console.WriteLine("{0}: Arf", Name);
            Mood = 1;
        }
        public void AngryNoise(int noiseLevel)
        {
            string angryNoise = "Grr";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "r";
            Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }
        public void HappyReaction()
        {
            Console.WriteLine("{0}: Wag wag Wag", Name);
        }

        public void AngryReaction()
        {
            Console.WriteLine("{0}: Bite - Ouch", Name);
        }
    }

    // Cat - inherits from Animal and implements INoise and IReaction
    public class Cat : Animal, INoise, IReaction
    {
        public void HappyNoise()
        {
            System.Console.WriteLine("{0}: Meow", Name);
            Mood = 1;
        }
        public void AngryNoise(int noiseLevel)
        {
            string angryNoise = "Hiss";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "s";
            System.Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }

        public void HappyReaction()
        {
            Console.WriteLine("{0}: Pur pur pur", Name);
        }

        public void AngryReaction()
        {
            Console.WriteLine("{0}: Scratch - Ouch", Name);
        }
    }

    class Program
    {

        static void Header()
        {
            Console.WriteLine("************************************************************");
            Console.WriteLine("***      Interface Example: Dogs and Cats                ***");
            Console.WriteLine("***                                                      ***");
            Console.WriteLine("***        1. Implements two interfaces.                 ***");
            Console.WriteLine("***        2. Inherits from a class.                     ***");
            Console.WriteLine("************************************************************\n");
        }

        static void Main()
        {
            Header();

            Dog Holly = new Dog() { Name = "Holly" };
            Cat Shadow = new Cat() { Name = "Shadow" };
            Holly.HappyNoise();
            Shadow.HappyNoise();
            System.Console.WriteLine();

            Holly.AngryNoise(4);
            Shadow.AngryNoise(6);
            Console.WriteLine();

            switch (Holly.Mood)
            {
                case 3:
                    Console.WriteLine("{0}: I am getting angry.", Holly.Name);
                    break;
                case 2:
                    Console.WriteLine("{0}: I do not like that.", Holly.Name);
                    break;
                default:
                    if (Holly.Mood > 3)
                        Holly.AngryReaction();
                    else
                        Holly.HappyReaction();
                    break;
            }

            switch (Shadow.Mood)
            {
                case 2:
                    Console.WriteLine("{0}: I am getting angry.", Shadow.Name);
                    break;
                case 1:
                    Console.WriteLine("{0}: I do not like that.", Shadow.Name);
                    break;
                default:
                    if (Shadow.Mood > 2)
                        Shadow.AngryReaction();
                    else
                        Shadow.HappyReaction();
                    break;
            }
            Console.WriteLine();
        }
    }
}

Top



Interface with Extension Method

.Interface with Extension Method


Interface with Extension Method - Program Output

This program is similar to the preceding example except it adds and extension method to extend the IReaction interface with a ScaredReaction() behavior.

using System;
namespace InterfaceExtended
{
    // Extension Method of IReaction Interface
    public static class MyExtensionMethods
    {
        public static void ScaredReaction(this IReaction reaction)
        {
            Console.WriteLine("{0}: Run, run, run.", reaction);
        }
    }

    // Noise Interface
    public interface INoise
    {
        void HappyNoise();
        void AngryNoise(int noiseLevel);
    }

    // Reaction Interface
    public interface IReaction
    {
        void HappyReaction();
        void AngryReaction();
    }

    // Base Animal Class
    public class Animal
    {
        public string Name { get; set; }
        public int Mood { get; set; }
        public Animal() { Name = ""; Mood = 0; }
    }

    // Dog - inherits from Animal and implements INoise and IReaction
    public class Dog : Animal, INoise, IReaction
    {
        public void HappyNoise()
        {
            Console.WriteLine("{0}: Arf", Name);
            Mood = 1;
        }
        public void AngryNoise(int noiseLevel)
        {
            string angryNoise = "Grr";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "r";
            Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }
        public void HappyReaction()
        {
            Console.WriteLine("{0}: Wag wag Wag", Name);
        }

        public void AngryReaction()
        {
            Console.WriteLine("{0}: Bite - Ouch", Name);
        }
    }

    // Cat - inherits from Animal and implements INoise and IReaction
    public class Cat : Animal, INoise, IReaction
    {
        public void HappyNoise()
        {
            System.Console.WriteLine("{0}: Meow", Name);
            Mood = 1;
        }
        public void AngryNoise(int noiseLevel)
        {
            string angryNoise = "Hiss";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "s";
            System.Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }

        public void HappyReaction()
        {
            Console.WriteLine("{0}: Pur pur pur", Name);
        }

        public void AngryReaction()
        {
            Console.WriteLine("{0}: Scratch - Ouch", Name);
        }
    }

    class Program
    {

        static void Header()
        {
            Console.WriteLine("************************************************************");
            Console.WriteLine("***      Interface Example: Dogs and Cats                ***");
            Console.WriteLine("***                                                      ***");
            Console.WriteLine("***  1. Class implements multiple (two) interfaces.      ***");
            Console.WriteLine("***  2. Interfaces are inherited along with base class.  ***");
            Console.WriteLine("***  3. An extension method extends an interface.        ***");
            Console.WriteLine("************************************************************\n");
        }

        static void Main()
        {
            Header();

            Dog Holly = new Dog() { Name = "Holly" };
            Cat Shadow = new Cat() { Name = "Shadow" };
            Holly.HappyNoise();
            Shadow.HappyNoise();
            System.Console.WriteLine();

            // Exetended Interface
            Holly.ScaredReaction();

            Holly.AngryNoise(4);
            Shadow.AngryNoise(6);
            Console.WriteLine();

            switch (Holly.Mood)
            {
                case 3:
                    Console.WriteLine("{0}: I am getting angry.", Holly.Name);
                    break;
                case 2:
                    Console.WriteLine("{0}: I do not like that.", Holly.Name);
                    break;
                default:
                    if (Holly.Mood > 3)
                        Holly.AngryReaction();
                    else
                        Holly.HappyReaction();
                    break;
            }

            switch (Shadow.Mood)
            {
                case 2:
                    Console.WriteLine("{0}: I am getting angry.", Shadow.Name);
                    break;
                case 1:
                    Console.WriteLine("{0}: I do not like that.", Shadow.Name);
                    break;
                default:
                    if (Shadow.Mood > 2)
                        Shadow.AngryReaction();
                    else
                        Shadow.HappyReaction();
                    break;
            }
            Console.WriteLine();
        }
    }
}

Top



Refactored with Additional ICatcher<T> Generic Interface

.ICatcher Interface


Refactored, New Generic Interface Added - Program Output

This program is similar to the preceding examples except it has been refactored to move the INoise and IReaction interfaces up into the Animal base class. Dog and Cat now receive these interfaces from the base Animal class. A new ICatcher generic interface was added and is only valid for the Dog type. A total of 10 Dogs and Cats are created and upcast as Animals for storage in an Animal array. foreach is used to examine each Animal in the array and uses the is operator to determine if the Animal is a Dog or a Cat. The mood is adjusted differently for Dogs than it is for Cats. If the Dog's mood is too bad, then the ICatcher.CallCatcher() method is invoked.

using System;
namespace CatLady
{
    // Noise Interface
    public interface INoise
    {
        void HappyNoise();
        void AngryNoise(int noiseLevel);
    }

    // Reaction Interface
    public interface IReaction
    {
        void HappyReaction();
        void AngryReaction();
    }

    // Interface Catcher
    public interface ICatcher<T> where T: Dog
    {
        void CallCatcher();
    }

    // Base Animal Class - implements INoise and IReaction
    public class Animal : INoise, IReaction
    {
        public string Name { get; set; }
        public int Mood { get; set; }
        public Animal() { Name = ""; Mood = 0; }

        public virtual void HappyNoise()
        {
            Console.WriteLine("{0}: happy noise", Name);
            Mood = 1;
        }
        public virtual void AngryNoise(int noiseLevel)
        {
            string angryNoise = "angry angry ";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "r";
            Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }
        public virtual void HappyReaction()
        {
            Console.WriteLine("{0}: happy reaction", Name);
        }

        public virtual void AngryReaction()
        {
            Console.WriteLine("{0}: angry reaction", Name);
        }
    }


    // Dog - inherits from Animal, implements ICatcher
    public class Dog : Animal, ICatcher<Dog>
    {
        public void CallCatcher()
        {
            Console.WriteLine("Call the catcher for this beast");
        }

        public override void HappyNoise()
        {
            Console.WriteLine("{0}: Arf", Name);
            Mood = 1;
        }
        public override void AngryNoise(int noiseLevel)
        {
            string angryNoise = "Grr";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "r";
            Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }
        public override void HappyReaction()
        {
            Console.WriteLine("{0}: Wag wag Wag", Name);
        }

        public override void AngryReaction()
        {
            Console.WriteLine("{0}: Bite - Ouch", Name);
        }
    }

    // Cat - inherits from Animal
    public class Cat : Animal
    {
        public override void HappyNoise()
        {
            System.Console.WriteLine("{0}: Meow", Name);
            Mood = 1;
        }
        public override void AngryNoise(int noiseLevel)
        {
            string angryNoise = "Hiss";
            for (int i = 0; i < noiseLevel; i++)
                angryNoise += "s";
            System.Console.WriteLine("{0}: {1}", Name, angryNoise);
            Mood = noiseLevel / 2;
        }

        public override void HappyReaction()
        {
            Console.WriteLine("{0}: Pur pur pur", Name);
        }

        public override void AngryReaction()
        {
            Console.WriteLine("{0}: Scratch - Ouch", Name);
        }
    }

    class Program
    {
        static void Header()
        {
            Console.WriteLine("************************************************************");
            Console.WriteLine("***  Interface Example: Too Many Dogs and Cats           ***");
            Console.WriteLine("***                                                      ***");
            Console.WriteLine("***    1. Base class implements two interfaces.          ***");
            Console.WriteLine("***    2. A derived class implements one more interface. ***");
            Console.WriteLine("***    3. 10 cats and dogs are upcast into Animal array. ***");
            Console.WriteLine("***    4. \"is\" checks Animal to see implements ICatcher. ***");
            Console.WriteLine("***    5. If implements ICatcher, cast interface.        ***");
            Console.WriteLine("************************************************************\n");
        }

        static void Main()
        {
            int catMood = 0;
            int dogMood = 0;

            Header();

            // Upcast and store in Animal array
            Animal[] myAnimals = new Animal[10];
            myAnimals[0] = new Dog() { Name = "Holly" };
            myAnimals[1] = new Dog() { Name = "Ginger" };
            myAnimals[2] = new Dog() { Name = "Freckles" };
            myAnimals[3] = new Dog() { Name = "Fido" };
            myAnimals[4] = new Cat() { Name = "Shadow" };
            myAnimals[5] = new Cat() { Name = "Tessa" };
            myAnimals[6] = new Cat() { Name = "Tucker" };
            myAnimals[7] = new Cat() { Name = "Pepper" };
            myAnimals[8] = new Cat() { Name = "Jack" };
            myAnimals[9] = new Cat() { Name = "Kitty" };

            foreach (Animal animal in myAnimals)
            {
                animal.HappyNoise();
                animal.AngryNoise((animal is Cat) ? catMood : dogMood);
                if (animal is Cat)
                    catMood += 2;
                else if (animal is Dog)
                    dogMood += 3;

                switch (animal.Mood)
                {
                    case 3:
                        Console.WriteLine("{0}: I am getting angry.", animal.Name);
                        break;
                    case 2:
                        Console.WriteLine("{0}: I do not like that.", animal.Name);
                        break;
                    default:
                        if (animal.Mood > 3)
                        {
                            animal.AngryReaction();
                            // If the Animal implements ICatcher,
                            // cast interface and call
                            if (animal is ICatcher<Dog>)
                            {
                                ICatcher<Dog> theAnimal = (ICatcher<Dog>)animal;
                                theAnimal.CallCatcher();
                            }
                        }
                        else
                        {
                            animal.HappyReaction();
                        }

                        break;
                }
                Console.WriteLine();
            }
        }
    }
}

Top


Reference Articles

Top