#1,161 – Explicit Implementation of Events in Interface

If you implement an event defined in an interface explicitly, you must use event accessor syntax, defining both add and remove accessors.

    public interface IDogEvents
    {
        event EventHandler Barked;
        event EventHandler Escaped;
    }

    public class Dog : IDogEvents
    {
        public string Name { get; set; }
        public bool IsPresent { get; set; }

        public Dog(string name)
        {
            Name = name;
            IsPresent = true;
        }

        public void Bark()
        {
            Console.WriteLine("Woof");
            if (IsPresent)
                barked(this, EventArgs.Empty);
            else
                escaped(this, EventArgs.Empty);
        }

        private EventHandler barked;
        event EventHandler IDogEvents.Barked
        {
            add { barked += value; }
            remove { barked -= value; }
        }

        private EventHandler escaped;
        event EventHandler IDogEvents.Escaped
        {
            add { escaped += value; }
            remove { escaped -= value; }
        }
    }

You can then add an event handler by using an interface reference.

        static void Main(string[] args)
        {
            Dog d = new Dog("Bob");
            IDogEvents ide = (IDogEvents)d;
            ide.Barked += d_Barked;
            d.Bark();
        }

#1,031 – Requiring Generic Type Parameters to Implement an Interface

By default, when you specify a type parameter in a generic class, the type can be any .NET type.  There are times, however, when you’d like to constrain the type in some ways, allowing only types that implement a particular interface.

You can constrain a type parameter to be of a type that implements a particular interface, using the where keyword.  In the example below, the PileOf class has a type parameter that must be a type that implements the IBark interface.  (The EverybodyBark method calls a method in IBark).

    public class PileOf<T> where T : IBark
    {
        private List<T> thePile;

        public PileOf()
        {
            thePile = new List<T>();
        }

        public void AddThing(T thing)
        {
            thePile.Add(thing);
        }

        public void EverybodyBark()
        {
            foreach (T creature in thePile)
            {
                creature.Bark();
            }
        }
    }

We can now create a PileOf<Dog>, because Dog implements IBark, but we can’t create a PileOf<Cow>.

#781 – A struct Can Implement an Interface

Like a class, a struct can implement an interface.  In the example below, the DogCollar struct implements the IStrapDimensions interface, which contains a couple of properties and a method.

    public interface IStrapDimensions
    {
        double Length { get; }
        double Width { get; }

        double CalcArea();
    }

    public struct DogCollar : IStrapDimensions
    {
        private double length;
        public double Length
        {
            get { return length; }
        }

        private double width;
        public double Width
        {
            get { return width; }
        }

        public double CalcArea()
        {
            return Length * Width;
        }

        public DogCollar(double len, double wid)
        {
            length = len;
            width = wid;
        }
    }

#766 – Adding an Interface to a Class Diagram

If you add a class to a class diagram and the class implements one or more interfaces, you’ll see the interfaces show up on the class with the standard interface designator (a short line with a circle at the end).

766-001

 

You can also add an element to the class diagram that represents the interface itself.  To do this, just right-click on an interface and select Show Interface.

766-002

 

Once you do this, the interface will be added to the diagram.  You can then expand the basic element to see the members of the interface.

766-003

#626 – Nested Type Options

When you declare one type inside of another, the outer type must be either a class or a struct.  The inner (nested) type can be one of the following: class, struct, interface, delegate or enum.

Here are a few common examples.

A struct in a class:

    public class Dog
    {
        public string Name { get; set; }

        public struct DogCollar
        {
            public int Length;
            public string Material;
        }
    }

A delegate type  defined in a class:

    public class Dog
    {
        public string Name { get; set; }

        public delegate void BarkHandler(object sender, BarkEventArgs e);
    }

An enum in a class:

    public class Dog
    {
        public string Name { get; set; }

        public enum Temperament { Docile, Excitable, Vicious };
    }

#437 – Access Interface Members through an Interface Variable

Once a class implements a particular interface, you can interact with the members of the interface through any instance of that class.

            Cow bossie = new Cow("Bossie", 5);

            // Cow implements IMoo, which includes Moo method
            bossie.Moo();

You can also declare a variable whose type is an interface, assign it to an instance of any class that implements that interface and then interact with members of the interface through that interface variable.

            // bossie is a Cow, which implements IMoo, so we can point IMoo variable at her
            IMoo mooer = bossie;
            mooer.Moo();

In either case, we end up calling the same Moo method.

Notice that we can’t access members of Cow that aren’t part of IMoo using this interface variable.

Even though MakeSomeMilk is a public method in the Cow class, we can’t access it via IMoo.

#436 – The Implementation of an Interface Can Be a Subset of the Class

When a class implements an interface, it is declaring that it implements all members of the interface.  Client code can interact with an instance of the class through the members of the interface.  It can also interact with class members that are not part of the interface.

For example, assume that the Cow class implements the IMoo interface, which contains the Moo method.  Client code can invoke the Moo method on instances of the Cow class, since it implements IMoo.

            Cow bossie = new Cow("Bossie", 5);

            // Invoke IMoo.Moo
            bossie.Moo();

Clients can also call methods that are not part of the IMoo interface.

            // Call methods and set properties that are NOT part of IMoo
            bossie.MakeSomeMilk();
            bossie.Motto = "Docile but still a maverick";