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

C# Object to Interface Caster Utility

, 28 Apr 2009
Rate this:
Please Sign up or sign in to vote.
A utility that casts an object to an interface, even if it doesn't formally implement it.

Introduction

In this article, 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 an idea of what I’m trying to propose here, consider the examples below.

Let's say you’re utilizing third party libraries (LibA and LibB) that are dealing with persons. These libraries have the PersonLibA and PersonLibB classes defined, and are exposing instances of these persons. Most likely, they would expose a 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 have the source code of these components, you could define a common interface and implement the 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 the person classes and implement the common interface.

Similarly, if you want to access the Text property of a 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 third 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 a wrapper class on the 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 a single public method, T As(object o), which gets any kind of object, and returns the 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 the ObjectCaster class and converts an instance of the Person class to the 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 = "Steve";

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 the code above, you will easily notice that the object does not formally implement the IPerson interface, and correctly wraps the properties, methods, and events. You may also notice that the wrapped event handler modifies the value of the original sender (which is an instance of Person) to an instance of the converted wrapper object (iperson variable).

binary_CSharp_Object_Caster

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 the System.CodeDom machinery, which wraps the sourceType and implements the interfaceType interface. With the help of .NET Reflection, it goes over the members of the interfaceType type and generates the corresponding members in the proxy class. After that, it compiles the generated class utilizing the CodeDomProvider class and calling the 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. The full source code for the utility class and the demo application are available above in the downloads section.

Future work

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

Origin

The origin of this article can be found at: C# Object to Interface Caster Utility.

History

  • 26 April, 2009 - Fixed a bug to support non GACed assemblies. Thanks to Oleg Shilo.
  • 25 April, 2009 - Initial version.

License

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

About the Author

Ruben Hakopian
Software Developer (Senior) Independent Contractor
United States United States

Comments and Discussions

 
GeneralThoughts PinmemberPIEBALDconsult27-Apr-09 17:12 
GeneralRe: Thoughts PinmemberRuben Hakopian27-Apr-09 18:17 
GeneralRe: Thoughts [modified] Pinmemberveki-peki28-Apr-09 2:23 
GeneralRe: Thoughts PinmemberRuben Hakopian28-Apr-09 7:50 
GeneralRe: Thoughts Pinmemberveki-peki28-Apr-09 20:15 
GeneralRe: Thoughts PinmemberPIEBALDconsult28-Apr-09 4:50 
GeneralRe: Thoughts PinmemberRuben Hakopian28-Apr-09 7:42 
GeneralRe: Thoughts Pinmemberveki-peki28-Apr-09 2:35 
GeneralRe: Thoughts PinmemberPIEBALDconsult28-Apr-09 4:45 
GeneralRe: Thoughts PinmemberRuben Hakopian28-Apr-09 7:59 
QuestionHave you checked LinFu? Pinmemberveki-peki27-Apr-09 1:21 
AnswerRe: Have you checked LinFu? PinmemberRuben Hakopian27-Apr-09 10:42 
GeneralWorking with non-GAC assemblies PinmemberOleg Shilo26-Apr-09 16:49 
GeneralRe: Working with non-GAC assemblies PinmemberRuben Hakopian26-Apr-09 17:26 
GeneralRe: Working with non-GAC assemblies Pinmembertrialtrial200726-Aug-09 5:32 
GeneralThis is huge... PinmemberOleg Shilo26-Apr-09 14:17 
GeneralRe: This is huge... PinmemberRuben Hakopian26-Apr-09 16:59 
Oleg,
 
I appreciate your feedback, and that would be an honour to me if you use my utility in your scripting engine. So, I give you a full permission to use my ObjectCaster class as a part of your CS-Script(www.csscript.net) engine.
 
I also liked your idea of adding robust C# scripting ability vs poor VB and batch scripts. At some time would like to be more familiar with your engine.
 
Udachi,
Ruben.
GeneralRe: This is huge... Pinmemberveki-peki28-Apr-09 2:31 
GeneralRe: This is huge... PinmemberOleg Shilo28-Apr-09 3:18 
GeneralRe: This is huge... PinmemberRuben Hakopian28-Apr-09 7:31 
GeneralInteresting idea PinmemberJoe Enos25-Apr-09 16:24 
GeneralRe: Interesting idea PinmemberRuben Hakopian25-Apr-09 17:04 

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
Web04 | 2.8.140721.1 | Last Updated 28 Apr 2009
Article Copyright 2009 by Ruben Hakopian
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid