Created
October 28, 2014 02:58
-
-
Save SLaks/a4b4d20e666d0b19beca to your computer and use it in GitHub Desktop.
Creates a shim to make an object implement a compatible interface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unfortunately, this throws "Type is attempting to implement an inaccessible interface.", and there is no workaround