Home > .NET, C# > C# Object To Interface Caster Utility

C# Object To Interface Caster Utility

April 23rd, 2009 Leave a comment Go to comments

Introduction

Here I describe a unique way of casting any object to an interface that it actually exposes, even though it does not formally implement the particular interface. In order to get the idea what I’m trying to propose here, consider examples below.

Lets say you’re utilizing 3rd party libraries(LibA and LibB) that are dealing with persons. These libraries have PersonLibA and PersonLibB classes defined and are exposing instances of these persons. Most likely they would expose similar public interface and would have properties like Name, EMail, Address, DateOfBirth, etc.  I’m almost sure that you would like to access these persons uniformly. If you had the source code of these components, you could define a common interface and implement PersonLibA and PersonLibB classes from your newly defined interface. However, if the source code is not available that would not work out. The only thing left to do is to define wrapper classes for each of person classes and implement the common interface.

Similarly, if you want to access the Text property of WPF TextBox and TextBlock uniformly, you would most probably need to define two wrapper classes to expose the Text property.

It can be done easily if there are not so many 3rd party classes involved and the common interface is simple enough. Otherwise, this process would be really painful. What I suggest here is a utility class that casts an object to an interface by generating wrapper class on fly and doing all the dirty work for you behind the scenes. I will go straight to the usage and later on will present some tricks used in the solution.

Using the code

The utility comes as a template class where T is the the interface to convert to. It has the only single public method – T As(object o) which gets any kind of object and returns converted wrapper object if succeeded.

public static class ObjectCaster<T>
{
    public static T As(object o)
    {
        // ....
    }
}

Consider the following Person class. Note that it does not implement any interface.

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

    public event EventHandler Initialized;

    public void Initialize()
    {
        Name = "Initialized";
        EventHandler e = Initialized;
        if (e != null)
            e(this, EventArgs.Empty);
    }
}

However, it is perfectly aligned with the following interface:

public interface IPerson
{
    string Name { get; set; }

    event EventHandler Initialized;

    void Initialize();
}

Below is the actual demo code which utilizes ObjectCaster class and converts an instance of Person class to IPerson interface (line 4).

Person obj = new Person() { Name = "John" };
Console.WriteLine(string.Format("(obj is IPerson) == {0}", obj is IPerson));

IPerson iperson = ObjectCaster<IPerson>.As(obj);
iperson.Initialized += ((sender, e) => Console.WriteLine("Initialized Called"));

Console.WriteLine("Person> " + obj.Name);
Console.WriteLine("IPerson> " + iperson.Name);

iperson.Name = &quot;Steve&quot;;

Console.WriteLine("Person> " + obj.Name);
Console.WriteLine("IPerson> " + iperson.Name);

iperson.Initialize();

Console.WriteLine("Person> " + obj.Name);
Console.WriteLine("IPerson> " + iperson.Name);

As you see the output of code above, you will easily notice that the object does not formally implement IPerson interface, and correctly wraps properties, methods and events. You may also notice, that wrapped event handler modifies the value of original sender (which is instance of Person) to instance of converted wrapper object (iperson variable).

Object Caster Demo Application Screenshot

Background

The key point of the solution is concentrated in the GenerateProxyClass method:

private static CodeCompileUnit GenerateProxyClass(Type interfaceType, Type sourceType)
{
    //...
}

Basically, it generates a new proxy class using System.CodeDom machinery, which wraps the sourceType and implements the interfaceType interface. With the help of .NET Reflections it goes over members of interfaceType type and generates corresponding members in the proxy class. After it compiles the generated class utilizing CodeDomProvider class and calling CompileAssemblyFromDom method. At this point the generated class is compiled and the last thing to do is to create a new instance of the proxy class, and provide the source object as a constructor. Full source code for the utility class and demo application are available below in the downloads section.

Future Work

Next thing to do on this topic is to provide an ability to remap member naming and add type conversion. It will allow to cast to same an interface even though name and type of members are not the same in the interface and source classes.

Downloads

Attached Files:

  1. May 19th, 2009 at 02:29 | #1

    hh.. thank you :)

  2. avatar
    vazoffsky
    May 25th, 2009 at 03:36 | #2

    hey dude!
    this is a great idea… but still are you seriously considering
    using this in a large project? one thing is to use reflections when you actually know what you are doing and completely another to generate code based on code reflection. I’m sure you yourself can imagine tons of situations when this can be not only dangerous… but also cause very hard to detect problems.

    cheers :)

  3. avatar
    ruben hakopian
    June 2nd, 2009 at 02:58 | #3

    I would really recommend using it in a large/performance critical project IF and ONLY if you are using lots of 3rd party components and you want to work with them uniformly. Consider this utility as a “software coder” (not engineer :) , who develops a wrapper class, which implements the interface you need. Lets say you have a class A and interface IHaveName:

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

    interface IHaveName
    {
    string Name { get; }
    }

    this utility generates following wrapper class

    class A_Wrapper : IHaveName
    {
    private A _a;

    public A_Wrapper(A a) { _a = a; }

    public string Name
    {
    get { return _a.A; }
    }
    }

    So, if you need to develop a class “A_Wrapper” for any “A” class and “IHaveName” interface, so let this utility to code/compile and create the instance of this “A_Wrapper” wrapper. If you have a clear understanding what kind of wrapper it generates, then I don’t think you might have any problem with it.

    If you have tons of these “A” classes and “IHaveName” interfaces then coding such “A_Wrapper” stupid classes for each of these pairs is quite painful process. I would rather make my “wrapper-software-coder” friend to code it for me during runtime :)

  4. avatar
    Korvus
    December 19th, 2009 at 08:43 | #4

    if (!interfaceType.IsInterface)
    throw new ArgumentException(“The generic type for ObjectCaster may be interface only.”);

    And WHY does it have to be an interface?

  5. December 29th, 2009 at 22:41 | #5

    @Korvus, the idea behind this utility is to emphasize the public interface of an object. For this purpose an interface is being used. Neither “class” nor a “struct” provide such a simple way of defining public members of an object as an “interface”. So I decided to restrict the function to use only interface types as a generic parameter.

    Please let me know if you need some further details.

  6. February 22nd, 2010 at 17:35 | #6

    Thanks for the great article. This gave me a few ideas for a framework I am working on that encapsulates use cases as objects. This has been helpful in visualizing some of the stickier parts of the idea.

  7. May 11th, 2010 at 02:30 | #7

    @Allen Paul de Rouen I’m glad it helps. I’m open for further cooperation.

    Thanks you.

  8. avatar
    Philippe Dykmans
    November 6th, 2010 at 12:33 | #8

    Works great! But there’s a bug also…

    A few lines in the As( object o ) method, it returns null if o is null. However, this code will never be reached. Because a few lines before you call o.GetType(). Which will throw a NullReferenceException if o is null.

    All in all, i have put the checks for null and ‘is T’ before anything else. Because there’s no use in doing checks if things can be returned as they are.

    Regards,
    Philippe

  9. November 9th, 2010 at 15:07 | #9

    @Philippe Dykmans
    Thank you! I will include it in the next version. I’ve got some more enhanced version to be ready soon. Please come back in couple of weeks to get it.

  1. No trackbacks yet.