Click here to Skip to main content
Click here to Skip to main content

Inversion of Control: Practical usage of Interface, Delegate or Events

, 16 Mar 2011
Rate this:
Please Sign up or sign in to vote.
Inversion of Control: Practical usage of Interface, Delegate or Events

Inversion of control is an architectural design principle which modifies the general flow of control of a program. You can say a program is a sequence of instructions that are running in a predefined sequence. Hence the sequence of execution of the program representing a sub-routine is defined when the class is actually implemented. Therefore, when the object is produced, it would have a sequence of instructions through which the control moves when it is called to execute. Inversion of control is a special circumstance where you will invert the predefined control flow to some arbitrary call defined way down the stream by the user who is actually using the component. In this post, I will show you how you can implement inversion of control in your code and also approaches which help you while implementing your own class.

You can generally implement inversion of control in C# using 3 approaches:

  1. Interface
  2. Delegate
  3. Event

Here, I will implement each of them with sample code.

Interface

Interface is the nicest concept for any modern programming. Most of us love to write interfaces while declaring our own types. There are a lots of interesting benefits of writing an interface. Some of them only deal with more structured code design, while others allows you a strict way of communication between objects. Interface plays an important role when you need inversion of control. Let me put forward a sample code to deal with inversion of control:

public interface ICaller
{
        void InvertedMember1();
        void InvertedMember2();
}
public class MyCustomClass
{
        public ICaller Caller { get; set; }

        //actual implementation

        public MyCustomClass(ICaller caller)
        {
            this.Caller = caller;
        }

        public void MyMethod()
        {
            Console.WriteLine("Start of method Body");

            Console.WriteLine("Let me call the first member of the caller :");

            this.Caller.InvertedMember1();

            Console.WriteLine("subroutine ends... now in MyMethod again");

            Console.WriteLine("hmm.. Now its time to call another method");

            this.Caller.InvertedMember2();

            Console.WriteLine("Back go MyMethod. Its time to bid you bye bye");

            Console.ReadLine();
        }
 }

Say you have a class with a method which implements the inversion of control. In my code, MyCustomClass requires to run some arbitrary method which the user of this class will provide later after the class is actually released to invert its control. For such reason, I have used an interface ICaller. The ICaller lets the class to call the method without actually implementing the code before calling the environment. The constructor ensures that when the object of the class is created, it needs an implementation of the object.

Note: You should always check if Caller is Null before calling its member. I removed it from the code just to make it simple.

public class CallerImplemented : ICaller
    {
        #region ICaller Members

        public void InvertedMember1()
        {
            Console.WriteLine("Oh I don't know when actually the call to 
				InvertedMember1 occurred");
        }

        public void InvertedMember2()
        {
            Console.WriteLine("Oh I don't know when actually the call to 
				InvertedMember2 occurred");
        }

        #endregion
    }

Now during the runtime of the project, when the object of MyCustomClass is created, I need an implementation of ICaller. Hence I write my own code within the implementation, and the library (or MyCustomClass) will invert the control to me while it is executing the method MyMethod.

For public API, it is very useful to have public interfaces so that user code can be hooked easily with the existing API. There are lots of Interfaces available with .NET which lets you hook your own code into their predefined API.

Pros & Cons

  • Very strict implementation required. You need to explicitly expose a Type to the API you are using.
  • Implementation of all the methods is required even though you don't want to invert your control for some other methods. In our case, if we do not want to invert my control for InvertedMember2, I cannot do it.

Delegate

Delegates are another important feature which promote inversion of control. Delegates are a special type which lets you wrap the reference of a method, and work just as an object. Hence when required, you can send your own method to the library and allow the library to call them, when required.

Delegates work great in C# as you have the option to send even anonymous delegates (which eventually a normal method in MSIL) and does not require to maintain a strong type declaration for a single method interface. Let us look at the code to see how we can use delegates to implement the same code:

public delegate void MyCustomDelegate();
    public class MyCustomClass
    {
        public MyCustomDelegate InvertedMember1 { get; set; }
        public MyCustomDelegate InvertedMember2 { get; set; }

        //actual implementation

        public MyCustomClass(MyCustomDelegate method1, MyCustomDelegate method2)
        {
            this.InvertedMember1 = method1;
            this.InvertedMember2 = method2;
        }

        public void MyMethod()
        {
            Console.WriteLine("Start of method Body");

            Console.WriteLine("Let me call the first member of the caller :");

            this.InvertedMember1();

            Console.WriteLine("subroutine ends... now in MyMethod again");

            Console.WriteLine("hmm.. Now its time to call another method");

            this.InvertedMember2();

            Console.WriteLine("Back go MyMethod. Its time to bid you bye bye");

            Console.ReadLine();
        }
    }

So almost the same code, with the use of delegate. We defined a public delegate type which can point to a method void(void) type. The properties are the actual objects which might get you a member which is sent from the client. Therefore the method which the client puts while creating object of this class will be called automatically when MyMethod is called.

Note: You should check if InvertedMember property is null before calling them in actual code. I intentionally removed it.

Now the call would look like:

MyCustomDelegate method1 = delegate()
  {
         Console.WriteLine("Oh I don't know when actually the call 
			to InvertedMember1 occurred");
  };
  MyCustomDelegate method2 = () =>
  {
          Console.WriteLine("Oh I don't know when actually the call 
			to InvertedMember2 occurred");
  };
  MyCustomClass cobj = new MyCustomClass(method1, method2);
  cobj.MyMethod();

Hence you can see, I have created two objects of MyCustomDelegate and assigned an anonymous delegate to it. I have used different syntax to make it clear that both represent the same thing.

You should note that I can even use normal method to associate with a delegate, just like anonymous methods.

Pros and Cons

  • Delegates are superior in the sense, it allows us to remove the maintenance of unnecessary types, even though they produce strong type in IL, and make our code cleaner.
  • You can make use of Action, Func generic delegates already present in the API, and hence remove unnecessary delegate declaration as well. I could have changed MyCustomDelegate with Action, and my code would work as it is.
  • Very useful when you want a short callback to execute.

Events

Finally, another option and somewhat the best approach for callbacks, is the use of events. Events act as a notification from a type. You can subscribe a method (or even more than one method) to a type to ensure that the method will be called whenever the class thinks to call.

Event system allows you to totally decouple the notification system with that of the actual type. Hence it also ensures that the object will invert its control only when there is active subscription available. Now let us change the code a little so that it works with events.

public class MyCustomClass
    {

        private event Action _invertedMember1;
        public event Action InvertedMember1
        {
            add { this._invertedMember1 += value; }
            remove { this._invertedMember1 -= value; }
        }
        public virtual void OnInvertedMember1()
        {
            if (this._invertedMember1 != null)
                this._invertedMember1();
        }
        private event Action _invertedMember2;
        public event Action InvertedMember2
        {
            add { this._invertedMember2 += value; }
            remove { this._invertedMember2 -= value; }
        }
        public virtual void OnInvertedMember2()
        {
            if (this._invertedMember2 != null)
                this._invertedMember2();
        }        

        //actual implementation

        public MyCustomClass()
        {
        }

        public void MyMethod()
        {
            Console.WriteLine("Start of method Body");

            Console.WriteLine("Let me call the first member of the caller :");

            this.OnInvertedMember1();

            Console.WriteLine("subroutine ends... now in MyMethod again");

            Console.WriteLine("hmm.. Now its time to call another method");

            this.OnInvertedMember2();

            Console.WriteLine("Back go MyMethod. Its time to bid you bye bye");

            Console.ReadLine();
        }
    }

You can see that there is an event accessor defined for the events InvertedMember# which will let the subscription to work from outside to the actual event. The virtual OnInvertedMember# is just to check whether there is some active event or not. Null specifies there is no active subscription for the event.

From the method body, we call this virtual method to ensure that the event handlers (the method that we pass from outside for notification) will be called only when there is any active handler ready.

MyCustomClass cobj = new MyCustomClass();

cobj.InvertedMember1 +=  delegate()
{
      Console.WriteLine
	("Oh I don't know when actually the call to InvertedMember1 occurred");
};
cobj.InvertedMember2 += InvertedMember2;

cobj.MyMethod();


static void InvertedMember2()
        {
            Console.WriteLine
	      ("Oh I don't know when actually the call to InvertedMember2 occurred");
        }

Here, we separate the creation of the object with the event system. If we run without any active subscription, and call the MyMethod, it will write all the lines as it is. Once we subscribe, as in above, it will be called automatically by the event system. You can see the same output from it.

I have intentionally shown that event system can also be activated with normal method just like anonymous method.

.NET actually uses Delegate.Combine feature (MultiCastDelegate) to hold the method as you pass and invokes Delegate.Remove when you unsubscribe the event. So if you pass more than one method for the same event, both of them will be called when the event is raised.

cobj.InvertedMember1 +=  delegate()
            {
                Console.WriteLine("Oh I don't know when actually 
				the call to InvertedMember1 occurred");
            };
            cobj.InvertedMember1 += () => 
            {
                Console.WriteLine("Hey hey, this is another method..... ");
            };
            cobj.InvertedMember2 += InvertedMember2;

            cobj.MyMethod();

Thus the code above will produce output like this:

The line Hey hey, this is another method …. is called automatically when event is raised.

Conclusion

As you understand each of the bits, it is now good to tell you that each of these ways of inverting your control have its own pros and cons. There are certain cases where you want Interfaces, while others might require the use of events, it totally depends on your requirements and the one that suits your problem.

I hope you had fun reading the article, and hope to see some feedback.
Thank you for reading.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Abhishek Sur
Architect
India India
Did you like his post?
 
Oh, lets go a bit further to know him better.
Visit his Website : www.abhisheksur.com to know more about Abhishek.
 
Abhishek also authored a book on .NET 4.5 Features and recommends you to read it, you will learn a lot from it.
http://bit.ly/EXPERTCookBook
 
Basically he is from India, who loves to explore the .NET world. He loves to code and in his leisure you always find him talking about technical stuffs.
 
Presently he is working in WPF, a new foundation to UI development, but mostly he likes to work on architecture and business classes. ASP.NET is one of his strength as well.
Have any problem? Write to him in his Forum.
 
You can also mail him directly to abhi2434@yahoo.com
 
Want a Coder like him for your project?
Drop him a mail to contact@abhisheksur.com
 
Visit His Blog

Dotnet Tricks and Tips



Dont forget to vote or share your comments about his Writing
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralMy Vote of 5 Pinmvpthatraja29-Jan-12 10:09 
GeneralMy vote of 5 PinmemberSantanu Tripathy24-Apr-11 7:14 
GeneralMy vote of 5 Pinmemberjim lahey17-Mar-11 0:58 
GeneralNice PinmemberMihaiDanceu16-Mar-11 12:35 
GeneralMy vote of 5 PinmemberRaviRanjankr21-Feb-11 18:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140709.1 | Last Updated 16 Mar 2011
Article Copyright 2011 by Abhishek Sur
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid