#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";

#435 – Implementing an Interface

An interface is a list of class members that a class must implement if it chooses to implement the interface.

Assumed that we have the following IMoo interface.

    interface IMoo
    {
        // Methods
        void Moo();

        // Properties
        List<string> MooLog { get; set; }

        // Events
        event EventHandler<MooEventArgs> CowMooed;
    }

A class implements an interface by first listing the interface in the class declaration, as if it was inheriting from the interface.  It then provides implementations for all of the interface’s members.

    public class Cow : IMoo
    {
        //-- IMoo implementation --
        public void Moo()
        {
            string moo = "Moo !";
            Console.WriteLine("{0}: {1}", CowName, moo);
            MooLog.Add(moo);
            OnCowMooed(moo);
        }

        public List<string> MooLog { get; set; }

        public event EventHandler<MooEventArgs> CowMooed = delegate { };

        protected virtual void OnCowMooed(string mooPhrase)
        {
            CowMooed(this, new MooEventArgs(CowName, mooPhrase));
        }
        //-- IMoo implementation --

        public string CowName { get; set; }
    }

#434 – Interfaces

An interface is a list of methods, properties, events and indexers that a class may implement.  The declaration of an interface looks similar to a class declaration, but doesn’t contain an implementation for any of its members.

        public interface ICowHerd
        {
            // Properties
            string HerdName { get; set; }
            string HerdMotto { get; set; }
            List<CowInfo> Cows { get; set; }

            // Methods
            void DisplayHerdInfo();
            void DisplayCowInfo(int cowIndex);

            // Events
            event EventHandler<CowAddedEventArgs> CowAdded;
        }

You can’t do anything with an interface by itself. You can’t instantiate it like a class.  Instead, a class can choose to implement an interface, which means that it will define an implementation for every member of the interface.  You can think of the interface as a contract that dictates the exact members that a class must implement if it decides to implement the interface.

 

#433 – All structs Inherit from System.ValueType

Unlike classes, user-defined structs do not support explicit inheritance.  You can’t inherit a struct from something else.  Instead, every user-defined struct implicitly inherits from System.ValueType, which in turn inherits from System.Object (object).

You also cannot ever explicitly inherit from System.ValueType.

#432 – Initialize Multiple Objects in a using Statement

The using statement defines the scope in which an object can be used, automatically calling the object’s Dispose method when it goes out of scope.

You can declare and initialize more than one object in a using statement, as long as they are all the same type.  All of the objects will be disposed when the scope of the using statement ends.

            using (StreamWriter writer = new StreamWriter(@"D:\Remember.txt"),
                   writer2 = new StreamWriter(@"D:\Legacy.txt"),
                   writer3 = new StreamWriter(@"D:\Clothing.txt"))
            {
                writer.Write("RIP Steve Jobs, 1955-2011");
                writer2.Write("Apple II, Macintosh, iMac, iPhone, iPad");
                writer3.Write("Jeans. Turtleneck.");
            }

#431 – The using Statement Automates Invocation of the Dispose Method

A class may implement the IDisposable interface, providing a Dispose method, to allow for deterministic destruction.  Client code calls Dispose when it is done using the object, telling it to release resources that it might be holding.

It can be hard to ensure that you always call Dispose when appropriate, especially when exceptions occur.

The using statement in C# specifies the scope in which you want to use an object and guarantees that the Dispose method will be called when the object goes out of scope.

            using (StreamWriter writer =
                new StreamWriter(@"D:\Remember.txt"))
            {
                writer.Write("RIP Steve Jobs, 1955-2011");
            }

If we look at the IL generated for the using statement, we can see that it is converted to a try/finally block and the Dispose method of the StreamWriter object is called in the finally block.