// Copyright (c) 2004, Rüdiger Klaehn
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// * Neither the name of lambda computing nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
namespace Lambda.Generic
{
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Collections.Generic;
/// <summary>
/// This is the base class for the automatically generated wrappers.
/// </summary>
public class WrapperBase
{
internal protected object src=null;
internal object NewFromPrototype(object src)
{
WrapperBase newWrapper = (WrapperBase)MemberwiseClone();
newWrapper.src = src;
return newWrapper;
}
}
/// <summary>
/// This internal class generates a wrapper type from one type to an interface
/// the type does not implement.
/// </summary>
internal class WrapperGenerator
{
static AppDomain appDomain;
static AssemblyBuilder asmBuilder;
static ModuleBuilder proxyModule;
static WrapperGenerator()
{
appDomain = Thread.GetDomain();
asmBuilder = appDomain.DefineDynamicAssembly(
new AssemblyName("Wrappers"),
AssemblyBuilderAccess.Run);
proxyModule = asmBuilder.DefineDynamicModule("WrapperModule", false);
}
/// <summary>
/// Generates a wrapper type using System.Reflection.Emit.
/// </summary>
/// <param name="tgt">The target type. Must be an interface</param>
/// <param name="src">The source type. Must contain all methods required for implementing the target type, but must not actually implement the target type.</param>
/// <returns>The wrapper type</returns>
/// <exception cref="System.MissingMethodException">if <paramref name="src"/> does not contain all required methods to implement <paramref name="dst"/></exception>
public static Type GenerateWrapperType(Type tgt, Type src)
{
Trace.Assert(tgt.IsInterface);
TypeBuilder proxyBuilder = proxyModule.DefineType(
src.Name + "To" + tgt.Name + "Wrapper",
TypeAttributes.NotPublic|TypeAttributes.Sealed,
typeof(WrapperBase),
new Type[] { tgt });
FieldInfo srcField=typeof(WrapperBase).GetField("src",BindingFlags.Instance|BindingFlags.NonPublic);
foreach (MethodInfo method in tgt.GetMethods())
{
ParameterInfo[] parameters = method.GetParameters();
Type[] parameterTypes = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
parameterTypes[i] = parameters[i].ParameterType;
MethodBuilder methodBuilder = proxyBuilder.DefineMethod(method.Name,
MethodAttributes.Public | MethodAttributes.Virtual
, method.ReturnType, parameterTypes);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
//load this
ilGenerator.Emit(OpCodes.Ldarg_0);
//load this->src
ilGenerator.Emit(OpCodes.Ldfld, srcField);
//push parameters on the stack
for (int i = 1; i < parameters.Length + 1; i++)
ilGenerator.Emit(OpCodes.Ldarg, i);
MethodInfo srcMethod = src.GetMethod(method.Name, parameterTypes);
if (srcMethod == null)
throw new MissingMethodException("The source type " + src.FullName + " does not contain the " + method.Name + " method " +
"required to implement the " + tgt.FullName + " interface!");
//call (virtual if nessecary)
if (method.IsVirtual)
ilGenerator.Emit(OpCodes.Callvirt, srcMethod);
else
ilGenerator.Emit(OpCodes.Call, srcMethod);
//return
ilGenerator.Emit(OpCodes.Ret);
}
return proxyBuilder.CreateType();
}
public static WrapperBase GenerateWrapperPrototype(Type tgt, Type src)
{
// emit a wrapper type to wrap T as implementing I.
// This is where an exception might be thrown.
Type wrapperType = GenerateWrapperType(tgt,src);
// create a prototype object because Activator.CreateInstance
// is too slow to use it every time.
return (WrapperBase)Activator.CreateInstance(wrapperType);
}
}
internal sealed class Latent<I, T>
{
static WrapperBase wrapperPrototype;
static Latent()
{
wrapperPrototype = WrapperGenerator.GenerateWrapperPrototype(typeof(I), typeof(T));
}
public static I Cast(T src)
{
return (I)wrapperPrototype.NewFromPrototype(src);
}
}
/// <summary>
/// A class that automatically generates wrapper classes for types that
/// implement all required methods for an interface, but do not explicitly
/// implement the interface. For example if you have an object <code>a</code>
/// of a type that contains a <code>int CompareTo(object o);</code> method but
/// does not implement the <code>IComparable</code> interface, you could
/// automatically create a wrapper using
/// <code>Latent<IComparable>.Cast(a);</code>
/// or
/// <code>Latent<IComparable>.CastObject(a);</code>
/// </summary>
/// <typeparam name="I">The interface to create wrappers for.</typeparam>
public sealed class Latent<I>
{
private static Dictionary<Type, WrapperBase> wrapperPrototypes = null;
private static WrapperBase GetWrapperPrototype(Type type)
{
if (wrapperPrototypes == null)
wrapperPrototypes = new Dictionary<Type, WrapperBase>();
if (wrapperPrototypes.ContainsKey(type))
return wrapperPrototypes[type];
else
return wrapperPrototypes[type] = WrapperGenerator.GenerateWrapperPrototype(typeof(I), type);
}
/// <summary>
/// The dynamic cast method. Generates a wrapper if nessecary, so the first invocation
/// for a new source type will take more time than subsequent invocations.
/// </summary>
/// <param name="src">The object to wrap.</param>
/// <returns>The wrapper, conveniently casted to <typeparamref name="I"/>.</returns>
/// <exception cref="System.MissingMethodException">if <paramref name="src"/> does not contain all required methods to implement <typeparamref name="I"/></exception>
public static I CastObject(object src)
{
if (typeof(I).IsAssignableFrom(src.GetType()))
return (I)src;
else
return (I)GetWrapperPrototype(src.GetType()).NewFromPrototype(src);
}
/// <summary>
/// The static cast method. Generates a wrapper if nessecary, so the first invocation
/// for a new source type will take more time than subsequent invocations.
/// </summary>
/// <param name="src">The object to wrap.</param>
/// <typeparam name="T">The type of the object to wrap</typeparam>
/// <returns>The wrapper, conveniently casted to <typeparamref name="I"/>.</returns>
/// <exception cref="System.MissingMethodException">if <paramref name="src"/> does not contain all required methods to implement <typeparamref name="I"/></exception>
public static I Cast<T>(T src)
{
return Latent<I, T>.Cast(src);
}
}
/// <summary>
/// This is a test interface
/// </summary>
interface ITest
{
void DoIt();
void Print(string a, string b);
void Print(int x, int y);
int Sum(int x, int y);
}
/// <summary>
/// This is a class that implements all required methods for the above
/// interface ITest, but does not explicitly implement the ITest interface.
/// </summary>
public class Test
{
//no parameters at all
public void DoIt()
{
Console.WriteLine("DoIt()");
}
//normal reference types
public void Print(string a, string b)
{
Console.WriteLine("Print({0},{1})", a, b);
}
//primitive types
public void Print(int i, int j)
{
Console.WriteLine("Print({0},{1})", i, j);
}
//return primitive types
public int Sum(int i, int j)
{
return i + j;
}
}
class TestMain
{
public static void Main()
{
try
{
Test test = new Test();
ITest itest = Latent<ITest>.Cast(test);
itest.DoIt();
itest.Print("Hello", "World");
itest.Print(1, 2);
Console.WriteLine(itest.Sum(1, 2));
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine(e.StackTrace);
}
}
}
}
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// * Neither the name of lambda computing nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
namespace Lambda.Generic
{
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Collections.Generic;
/// <summary>
/// This is the base class for the automatically generated wrappers.
/// </summary>
public class WrapperBase
{
internal protected object src=null;
internal object NewFromPrototype(object src)
{
WrapperBase newWrapper = (WrapperBase)MemberwiseClone();
newWrapper.src = src;
return newWrapper;
}
}
/// <summary>
/// This internal class generates a wrapper type from one type to an interface
/// the type does not implement.
/// </summary>
internal class WrapperGenerator
{
static AppDomain appDomain;
static AssemblyBuilder asmBuilder;
static ModuleBuilder proxyModule;
static WrapperGenerator()
{
appDomain = Thread.GetDomain();
asmBuilder = appDomain.DefineDynamicAssembly(
new AssemblyName("Wrappers"),
AssemblyBuilderAccess.Run);
proxyModule = asmBuilder.DefineDynamicModule("WrapperModule", false);
}
/// <summary>
/// Generates a wrapper type using System.Reflection.Emit.
/// </summary>
/// <param name="tgt">The target type. Must be an interface</param>
/// <param name="src">The source type. Must contain all methods required for implementing the target type, but must not actually implement the target type.</param>
/// <returns>The wrapper type</returns>
/// <exception cref="System.MissingMethodException">if <paramref name="src"/> does not contain all required methods to implement <paramref name="dst"/></exception>
public static Type GenerateWrapperType(Type tgt, Type src)
{
Trace.Assert(tgt.IsInterface);
TypeBuilder proxyBuilder = proxyModule.DefineType(
src.Name + "To" + tgt.Name + "Wrapper",
TypeAttributes.NotPublic|TypeAttributes.Sealed,
typeof(WrapperBase),
new Type[] { tgt });
FieldInfo srcField=typeof(WrapperBase).GetField("src",BindingFlags.Instance|BindingFlags.NonPublic);
foreach (MethodInfo method in tgt.GetMethods())
{
ParameterInfo[] parameters = method.GetParameters();
Type[] parameterTypes = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
parameterTypes[i] = parameters[i].ParameterType;
MethodBuilder methodBuilder = proxyBuilder.DefineMethod(method.Name,
MethodAttributes.Public | MethodAttributes.Virtual
, method.ReturnType, parameterTypes);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
//load this
ilGenerator.Emit(OpCodes.Ldarg_0);
//load this->src
ilGenerator.Emit(OpCodes.Ldfld, srcField);
//push parameters on the stack
for (int i = 1; i < parameters.Length + 1; i++)
ilGenerator.Emit(OpCodes.Ldarg, i);
MethodInfo srcMethod = src.GetMethod(method.Name, parameterTypes);
if (srcMethod == null)
throw new MissingMethodException("The source type " + src.FullName + " does not contain the " + method.Name + " method " +
"required to implement the " + tgt.FullName + " interface!");
//call (virtual if nessecary)
if (method.IsVirtual)
ilGenerator.Emit(OpCodes.Callvirt, srcMethod);
else
ilGenerator.Emit(OpCodes.Call, srcMethod);
//return
ilGenerator.Emit(OpCodes.Ret);
}
return proxyBuilder.CreateType();
}
public static WrapperBase GenerateWrapperPrototype(Type tgt, Type src)
{
// emit a wrapper type to wrap T as implementing I.
// This is where an exception might be thrown.
Type wrapperType = GenerateWrapperType(tgt,src);
// create a prototype object because Activator.CreateInstance
// is too slow to use it every time.
return (WrapperBase)Activator.CreateInstance(wrapperType);
}
}
internal sealed class Latent<I, T>
{
static WrapperBase wrapperPrototype;
static Latent()
{
wrapperPrototype = WrapperGenerator.GenerateWrapperPrototype(typeof(I), typeof(T));
}
public static I Cast(T src)
{
return (I)wrapperPrototype.NewFromPrototype(src);
}
}
/// <summary>
/// A class that automatically generates wrapper classes for types that
/// implement all required methods for an interface, but do not explicitly
/// implement the interface. For example if you have an object <code>a</code>
/// of a type that contains a <code>int CompareTo(object o);</code> method but
/// does not implement the <code>IComparable</code> interface, you could
/// automatically create a wrapper using
/// <code>Latent<IComparable>.Cast(a);</code>
/// or
/// <code>Latent<IComparable>.CastObject(a);</code>
/// </summary>
/// <typeparam name="I">The interface to create wrappers for.</typeparam>
public sealed class Latent<I>
{
private static Dictionary<Type, WrapperBase> wrapperPrototypes = null;
private static WrapperBase GetWrapperPrototype(Type type)
{
if (wrapperPrototypes == null)
wrapperPrototypes = new Dictionary<Type, WrapperBase>();
if (wrapperPrototypes.ContainsKey(type))
return wrapperPrototypes[type];
else
return wrapperPrototypes[type] = WrapperGenerator.GenerateWrapperPrototype(typeof(I), type);
}
/// <summary>
/// The dynamic cast method. Generates a wrapper if nessecary, so the first invocation
/// for a new source type will take more time than subsequent invocations.
/// </summary>
/// <param name="src">The object to wrap.</param>
/// <returns>The wrapper, conveniently casted to <typeparamref name="I"/>.</returns>
/// <exception cref="System.MissingMethodException">if <paramref name="src"/> does not contain all required methods to implement <typeparamref name="I"/></exception>
public static I CastObject(object src)
{
if (typeof(I).IsAssignableFrom(src.GetType()))
return (I)src;
else
return (I)GetWrapperPrototype(src.GetType()).NewFromPrototype(src);
}
/// <summary>
/// The static cast method. Generates a wrapper if nessecary, so the first invocation
/// for a new source type will take more time than subsequent invocations.
/// </summary>
/// <param name="src">The object to wrap.</param>
/// <typeparam name="T">The type of the object to wrap</typeparam>
/// <returns>The wrapper, conveniently casted to <typeparamref name="I"/>.</returns>
/// <exception cref="System.MissingMethodException">if <paramref name="src"/> does not contain all required methods to implement <typeparamref name="I"/></exception>
public static I Cast<T>(T src)
{
return Latent<I, T>.Cast(src);
}
}
/// <summary>
/// This is a test interface
/// </summary>
interface ITest
{
void DoIt();
void Print(string a, string b);
void Print(int x, int y);
int Sum(int x, int y);
}
/// <summary>
/// This is a class that implements all required methods for the above
/// interface ITest, but does not explicitly implement the ITest interface.
/// </summary>
public class Test
{
//no parameters at all
public void DoIt()
{
Console.WriteLine("DoIt()");
}
//normal reference types
public void Print(string a, string b)
{
Console.WriteLine("Print({0},{1})", a, b);
}
//primitive types
public void Print(int i, int j)
{
Console.WriteLine("Print({0},{1})", i, j);
}
//return primitive types
public int Sum(int i, int j)
{
return i + j;
}
}
class TestMain
{
public static void Main()
{
try
{
Test test = new Test();
ITest itest = Latent<ITest>.Cast(test);
itest.DoIt();
itest.Print("Hello", "World");
itest.Print(1, 2);
Console.WriteLine(itest.Sum(1, 2));
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine(e.StackTrace);
}
}
}
}


