Skip to main content

MEF or Managed Extensibility Framework and Lazy<T> – Being Lazy with MEF, Custom Export Attributes etc

Overview

The objective of this post is to brief how you can leverage the lazy initialization support available in MEF. We’ll examine MEF and Lazy, and then we’ll see how to use them together.

 

Preface About MEF

I hope you are already using Managed Extensibility Framework to build beautiful software. If you are not yet there, that is a crime, and I highly recommend you to read my introductory post on MEF. Let us start with another very basic MEF example. Let us get back our Zoo.

image 

We are composing our Zoo with a couple of Animals here.

    //Abstract animal interface
    interface IAnimal { void Eat(); }

    //Concrete animal 1
    [Export(typeof(IAnimal))]
    class Lion : IAnimal
    {
        public Lion() { Console.WriteLine("Grr.. Lion got created"); }
        public void Eat() { Console.WriteLine("Grr.. Lion eating meat"); }
    }

    //Concrete animal 2
    [Export(typeof(IAnimal))]
    class Rabbit : IAnimal
    {
        public Rabbit() { Console.WriteLine("Crrr.. Rabbit got created"); }
        public void Eat() { Console.WriteLine("Crrr.. Rabbit eating carrot"); }
    }
    
    //Our Zoo. MEF will inject animals to this zoo later, at the time of composition
    class Zoo
    {
        [ImportMany(typeof(IAnimal))]
        public IEnumerable<IAnimal> Animals { get; set; }
    }

    //Let us construct our zoo and animals
    class Program
    {
        static void Main(string[] args)
        {
            //Let us create a catalog and a container
            var catalog = new AssemblyCatalog(typeof(Program).Assembly);
            var container = new CompositionContainer(catalog);

            //Compose the zoo.
            var zoo = new Zoo();
            container.ComposeParts(zoo);

            //Let's feed our animals
            foreach (var animal in zoo.Animals)
                animal.Eat();

        }
    }

As you remember, a catalog is a sack full of types (cookies) to export. The container will fetch these exported types from the catalog, to instantiate and import them where ever applicable - based on the matching contracts specified in the Export and Import attributes. (Note to self - Shh!! don’t mention anything about ExportProvider and ExportDefinition now). In this case, we are using a type as the contract (IAnimal) for our Export and Import. And if you run that app, you’ll see.. hm.. a cute black screen. More importantly, you’ll see that MEF has created an instance of Lion and Rabbit at the time of composition – i.e, when we call container.ComposeParts. See the messages we are writing from the constructor.

image 

Note – If you want to be more realistic or if you hate animals in general, my advice is to think about your Business class instead of the Zoo, and think about some validation rules instead of those Animals. So that, you can plug in new validation rules with out affecting your entire system.

Preface About Lazy<T>

Oh yea, though MEF is seductive, let us stop thinking about that for a moment. Let us be a bit Lazy. You might have already heard about the Lazy<T> class in .NET 4.0. Lazy class allow you to support for lazy initialization. I.e, you can use Lazy<T> to defer the creation of a large or resource-intensive object, till you really need that.

Here is a quick example.

 

            //Let us be lazy about creating a lion
            Lazy<Lion> lazyLion = new Lazy<Lion>();

            //Do something else..

            //Actual object will be created here
            var lion = lazyLion.Value;
   

The interesting point to note is, you can defer the creation of your lion, till you really need it in your flow, probably inside an if block or so. Another interesting aspect of Lazy<T> is, you can specify your own factory method to create your object, via the Lazy<T> constructor. See this example.

            //Let us be lazy about creating our animal
            Lazy<IAnimal> lazyAnimal = new Lazy<IAnimal>(()=>new Lion());

            //Actual object will be created here
            var animal = lazyAnimal.Value;

Being Lazy with MEF

Now, let us see how to combine MEF and Lazy together. All right, you don’t really need to do anything special there – MEF already has some great support for Lazy. MEF can wire up your exports directly to a Lazy at the time of import. Now, let us see how to do that. We just need to make two modifications to our zoo example. Time for a KG Excercise - Spot the difference of this code example with the very first example.

 //Our zoo
    class Zoo
    {
        //** MODIFICATION 1 -You need to directly import to Lazy<IAnimal>
        [ImportMany(typeof(IAnimal))]
        public IEnumerable<Lazy<IAnimal>> Animals { get; set; }
    }

    //Abstract animal interface
    interface IAnimal { void Eat(); }

    //Concrete animal 1
    [Export(typeof(IAnimal))]
    class Lion : IAnimal
    {
        public Lion() { Console.WriteLine("Grr.. Lion got created"); }
        public void Eat() { Console.WriteLine("Grr.. Lion eating meat"); }
    }

    //Concrete animal 2
    [Export(typeof(IAnimal))]
    class Rabbit : IAnimal
    {
        public Rabbit() { Console.WriteLine("Crrr.. Rabbit got created"); }
        public void Eat() { Console.WriteLine("Crrr.. Rabbit eating carrot"); }
    }



    //Let us construct our zoo and animals
    class Program
    {
        static void Main(string[] args)
        {
            //Let us create a catalog and a container
            var catalog = new AssemblyCatalog(typeof(Program).Assembly);
            var container = new CompositionContainer(catalog);

            //Compose the zoo.
            var zoo = new Zoo();
            container.ComposeParts(zoo);

            //** MODIFICATION 2 - An instance will be created only when you access it
            //Use the Value property of the Lazy object to initialize and access the actual value
            foreach (var animal in zoo.Animals) 
                animal.Value.Eat();
        }
    }

And now, to understand how this changed the flow, let us run the application.

image

You’ll see that our animals are getting created only when we consume them – and not at the time of composing the zoo as we did earlier. 

Dealing with Metadata when MEF goes Lazy

MEF allows you to export Metadata along with the types you export. For example, assume that you want to specify whether your exported animals eat meat or not, so that some one can decide what to give them as food. One way is to use the ExportMetaData attribute with your exported types, as shown below.

   //Concrete animal 1
    [Export(typeof(IAnimal))]
    [ExportMetadata("EatMeat",true)]
    class Lion : IAnimal
    {
        public Lion() { Console.WriteLine("Grr.. Lion got created"); }
        public void Eat() { Console.WriteLine("Grr.. Lion eating meat"); }
    }

    //Concrete animal 2
    [Export(typeof(IAnimal))]
    [ExportMetadata("EatMeat", false)]
    class Rabbit : IAnimal
    {
        public Rabbit() { Console.WriteLine("Crrr.. Rabbit got created"); }
        public void Eat() { Console.WriteLine("Crrr.. Rabbit eating carrot"); }
    }
That looks a bit clumsy, because of those strings. Right? A better way is to create your own custom Export attribute that includes the metadata information as well. That is pretty simple. The code below is equivalent to what we have just done above. You see that we are creating a custom export attribute named ExportAnimal.
       //Our custom metadata attribute to exp animals
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    class ExportAnimal : ExportAttribute
    {
        //Pass the contract type to the base
        public ExportAnimal() : base(typeof(IAnimal)) { }
        //Additional metadata info
        public bool EatMeat { get; set; }
    }

    //Concrete animal 1
    [ExportAnimal(EatMeat=true)]
    class Lion : IAnimal
    {
        public Lion() { Console.WriteLine("Grr.. Lion got created"); }
        public void Eat() { Console.WriteLine("Grr.. Lion eating meat"); }
    }

    //Concrete animal 2
    [ExportAnimal(EatMeat = false)]
    class Rabbit : IAnimal
    {
        public Rabbit() { Console.WriteLine("Crrr.. Rabbit got created"); }
        public void Eat() { Console.WriteLine("Crrr.. Rabbit eating carrot"); }
    }
Now let us come to the real question. How to import the metadata information in a Lazy way? Fortunately, MEF has an overload of Lazy, Lazy that supports importing Metadata information. So, all we need to do is create a metadata import interface that matches our export definition, and use it. Like this.
   //An interface to import animal metadata
   //This should match the metadata we've in our custom export definition
    public interface IAnimalMetadata
    {
        bool EatMeat { get; }
    }

    //Our zoo
    class Zoo
    {
        //Directly import to Lazy<IAnimal,IAnimalMetadata>
        [ImportMany(typeof(IAnimal))]
        public IEnumerable<Lazy<IAnimal, IAnimalMetadata>> Animals { get; set; }
    }

So, here is the final piece that includes the above fragments. You can see that we are exporting our animals using a custom export attribute, and importing them in a lazy way along with the metadata. Then, Have a look at the Main method. You'll find that we are using the metadata to feed only the animals that eat meat.

In other words, the Lazy implementation provides you the luxury of initializing only the animals that you want to feed, at the time of feeding them - and not all the animals.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

namespace MefLazy
{

    #region Contracts

    //Abstract animal interface
    interface IAnimal { void Eat(); }

    #endregion

    #region Export Related

    //Our custom metadata attribute to exp animals
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    class ExportAnimal : ExportAttribute
    {
        //Pass the contract type to the base
        public ExportAnimal() : base(typeof(IAnimal)) { }
        //Additional metadata info
        public bool EatMeat { get; set; }
    }

    //Concrete animal 1
    [ExportAnimal(EatMeat = true)]
    class Lion : IAnimal
    {
        public Lion() { Console.WriteLine("Grr.. Lion got created"); }
        public void Eat() { Console.WriteLine("Grr.. Lion eating meat"); }
    }

    //Concrete animal 2
    [ExportAnimal(EatMeat = false)]
    class Rabbit : IAnimal
    {
        public Rabbit() { Console.WriteLine("Crrr.. Rabbit got created"); }
        public void Eat() { Console.WriteLine("Crrr.. Rabbit eating carrot"); }
    }

    #endregion

    #region Import Related

    //An interface to import animal metadata
    public interface IAnimalMetadata
    {
        bool EatMeat { get; }
    }

    //Our zoo
    class Zoo
    {
        //Directly import to Lazy<IAnimal,IAnimalMetadata>
        [ImportMany(typeof(IAnimal))]
        public IEnumerable<Lazy<IAnimal, IAnimalMetadata>> Animals { get; set; }
    }

    #endregion

    #region Main

    //Let us construct our zoo and animals
    class Program
    {
        static void Main(string[] args)
        {
            //Let us create a catalog and a container
            var catalog = new AssemblyCatalog(typeof(Program).Assembly);
            var container = new CompositionContainer(catalog);

            //Compose the zoo.
            var zoo = new Zoo();
            container.ComposeParts(zoo);

            //An instance will be created only when you access it
            //Use the Value property of the Lazy object to initialize and access the actual value
            //Let us feed only animals eating meat
            foreach (var animal in zoo.Animals) 
                if (animal.Metadata.EatMeat)
                    animal.Value.Eat();
        }
    }

    #endregion
}

Conclusion

I encourage you to apply these concepts to more practical scenarios. Like, instead of a Zoo, think about a RuleProcessor that runs a set of rules on a business object - and instead of an Animal, think about a Rule that can validate or process the business object. I’ll give some more practical examples pretty soon :). For now, the objective was to introduce Lazy concepts and MEF, and I hope you enjoyed the read. And you can download the final version of the code from the above link. Keep in touch, Follow me on twitter

Also, read my last post 4 .NET 4.0 Libraries You should know about

Happy Coding!!

Popular posts from this blog

Top 7 Coding Standards & Guideline Documents For C#/.NET Developers

Some time back, I collated a list of 7 Must Read, Free EBooks for .NET Developers, and a lot of people found it useful. So, I thought about putting together a list of Coding Standard guidelines/checklists for .NET /C# developers as well.As you may already know, it is easy to come up with a document - the key is in implementing these standards in your organization, through methods like internal trainings, Peer Reviews, Check in policies, Automated code review tools etc. You can have a look at FxCop and/or StyleCop for automating the review process to some extent, and can customize the rules based on your requirements.Anyway, here is a list of some good Coding Standard Documents. They are useful not just from a review perspective - going through these documents can definitely help you and me to iron out few hidden glitches we might have in the programming portion of our brain. So, here we go, the listing is not in any specific order.1 – IDesign C# Coding StandardsIDesign C# coding stand…

5 Awesome Learning Resources For Programmers (To help you and your kids to grow the geek neurons)

Happy New Year, this is my first post in 2012. I’ll be sharing few awesome learning resources I’ve bookmarked, and will be pointing out some specific computer/programming related courses I've found interesting from these resources.Also, thought about saving this blog post for my kids as well - instead of investing in these Child education schemes (though they are too small as of today, 2 years and 60 days respectively ). Anyway, personally my new year resolution is to see as much videos from this course collections (assuming I can find some free time in between my regular job && changing my babies diapers).1 – Khan AcademyAs I mentioned some time back, you and your kids are missing some thing huge if you havn’t heard about Khan Academy.  It is an awesome learning resource, especially if you want to re-visit your basics in Math, Science etc.With a library of over 2,600 videos covering everything from arithmetic to physics, finance, and history and 268 practice exercises, th…

Hack Raspberry Pi – How To Build Apps In C#, WinForms and ASP.NET Using Mono In Pi

Recently I was doing a bit of R&D related to finding a viable, low cost platform for client nodes. Obviously, I came across Raspberry Pi, and found the same extremely interesting. Now, the missing piece of the puzzle was how to get going using C# and .NET in the Pi. C# is a great language, and there are a lot of C# developers out there in the wild who are interested in the Pi.In this article, I’ll just document my findings so far, and will explain how develop using C# leveraging Mono in a Raspberry Pi. Also, we’ll see how to write few minimal Windows Forms & ASP.NET applications in the Pie as well.Step 1: What is Raspberry Pi?Raspberry Pi is an ARM/Linux box for just ~ $30. It was introduced with a vision to teach basic computer science in schools. How ever, it got a lot of attention from hackers all around the world, as it is an awesome low cost platform to hack and experiment cool ideas as Pi is almost a full fledged computer.  More About R-Pi From Wikipedia.The Raspberry Pi