Skip to content

Instantly share code, notes, and snippets.

@SLaks
Created October 28, 2014 02:58
Show Gist options
  • Save SLaks/a4b4d20e666d0b19beca to your computer and use it in GitHub Desktop.
Save SLaks/a4b4d20e666d0b19beca to your computer and use it in GitHub Desktop.
Creates a shim to make an object implement a compatible interface
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using Sigil.NonGeneric;
namespace VSThemeBrowser.VisualStudio {
static class ReflectionUtils {
static readonly AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("RoslynETAHost"), AssemblyBuilderAccess.Run);
static readonly ModuleBuilder module = assembly.DefineDynamicModule(assembly.GetName().Name);
///<summary>Compiles and instantiates an adapter class that implements an internal interface using a source instance that implements an equivalent interface.</summary>
public static object CreateInterfaceShim(Type targetInterface, object sourceObject) {
var typeBuilder = module.DefineType(targetInterface.FullName.Replace(".I", ".") + "Shim", TypeAttributes.Class, null, new[] { targetInterface });
var sourceType = sourceObject.GetType();
var field = typeBuilder.DefineField("instance", sourceType, FieldAttributes.Private);
var emitter = Emit.BuildConstructor(new[] { sourceType }, typeBuilder, MethodAttributes.Public);
emitter.LoadArgument(0);
emitter.LoadArgument(1);
emitter.StoreField(field);
emitter.Return();
emitter.CreateConstructor();
foreach (var targetMethod in targetInterface.GetMethods()) {
var parameterTypes = targetMethod.GetParameters().Select(p => p.ParameterType).ToArray();
emitter = Emit.BuildInstanceMethod(targetMethod.ReturnType, parameterTypes, typeBuilder, targetMethod.Name, targetMethod.Attributes & ~MethodAttributes.Abstract);
var sourceMethod = sourceType.GetMethod(targetMethod.Name, parameterTypes);
emitter.LoadArgument(0);
emitter.LoadField(field);
var targetParameters = targetMethod.GetParameters();
for (ushort i = 0; i < targetParameters.Length; i++) {
emitter.LoadArgument((ushort)(i + 1));
}
emitter.CallVirtual(sourceMethod);
emitter.Return();
emitter.CreateMethod();
}
return Activator.CreateInstance(typeBuilder.CreateType(), sourceObject);
}
}
}
@SLaks
Copy link
Author

SLaks commented Oct 28, 2014

Unfortunately, this throws "Type is attempting to implement an inaccessible interface.", and there is no workaround

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment