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).
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.