184 lines
7.6 KiB
C#
184 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
|
|
namespace CPF.Windows.Json.Deserialize
|
|
{
|
|
internal class InterfaceImplementation<TInterface>
|
|
{
|
|
public static readonly Type Proxy;
|
|
|
|
static InterfaceImplementation()
|
|
{
|
|
try
|
|
{
|
|
var iType = typeof(TInterface);
|
|
|
|
Random r = new Random();
|
|
var className = iType.Name + "Impl" + r.Next(int.MinValue, int.MaxValue).ToString();
|
|
while (AssemblyBuilderContainer.TypeNames.Contains(className))
|
|
className = iType.Name + "Impl" + r.Next(int.MinValue, int.MaxValue).ToString();
|
|
|
|
var typeBuilder =
|
|
AssemblyBuilderContainer.ModBuilder.DefineType(
|
|
className,
|
|
TypeAttributes.Class | TypeAttributes.Sealed,
|
|
typeof(object),
|
|
new[] { iType }
|
|
);
|
|
|
|
var allMembers = iType.GetAllInterfaceMembers();
|
|
|
|
List<MethodInfo> propertyInfos = new List<MethodInfo>();
|
|
|
|
foreach (var prop in allMembers.OfType<PropertyInfo>())
|
|
{
|
|
var propType = ReturnType(prop);
|
|
|
|
var propBuilder = typeBuilder.DefineProperty(prop.Name, prop.Attributes, propType, Type.EmptyTypes);
|
|
|
|
var iGetter = prop.GetMethod;
|
|
var iSetter = prop.SetMethod;
|
|
if (iGetter != null)
|
|
propertyInfos.Add(iGetter);
|
|
if (iSetter != null)
|
|
propertyInfos.Add(iSetter);
|
|
|
|
if (prop.Name == "Item")
|
|
{
|
|
if (iGetter != null)
|
|
{
|
|
var accessor = iGetter.Attributes;
|
|
accessor &= ~MethodAttributes.Abstract;
|
|
var methBuilder = typeBuilder.DefineMethod(iGetter.Name, accessor, iGetter.ReturnType, iGetter.GetParameters().Select(e => e.ParameterType).ToArray());
|
|
var il = methBuilder.GetILGenerator();
|
|
il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructors()[0]);
|
|
il.Emit(OpCodes.Throw);
|
|
propBuilder.SetGetMethod(methBuilder);
|
|
}
|
|
if (iSetter != null)
|
|
{
|
|
var accessor = iSetter.Attributes;
|
|
accessor &= ~MethodAttributes.Abstract;
|
|
var methBuilder = typeBuilder.DefineMethod(iSetter.Name, accessor, iSetter.ReturnType, iSetter.GetParameters().Select(e => e.ParameterType).ToArray());
|
|
var il = methBuilder.GetILGenerator();
|
|
il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructors()[0]);
|
|
il.Emit(OpCodes.Throw);
|
|
propBuilder.SetSetMethod(methBuilder);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
|
|
Func<FieldInfo> getBackingField;
|
|
{
|
|
FieldInfo backingField = null;
|
|
getBackingField =
|
|
() =>
|
|
{
|
|
if (backingField == null)
|
|
{
|
|
backingField = typeBuilder.DefineField("_" + prop.Name + "_" + Guid.NewGuid(), ReturnType(prop), FieldAttributes.Private);
|
|
}
|
|
|
|
return backingField;
|
|
};
|
|
}
|
|
|
|
if (iGetter != null)
|
|
{
|
|
var accessor = iGetter.Attributes;
|
|
accessor &= ~MethodAttributes.Abstract;
|
|
|
|
var methBuilder = typeBuilder.DefineMethod(iGetter.Name, accessor, propType, Type.EmptyTypes);
|
|
var il = methBuilder.GetILGenerator();
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldfld, getBackingField());
|
|
il.Emit(OpCodes.Ret);
|
|
propBuilder.SetGetMethod(methBuilder);
|
|
}
|
|
|
|
if (iGetter != null || iSetter != null)
|
|
{
|
|
var accessor = iSetter != null ? iSetter.Attributes : MethodAttributes.Private;
|
|
var name = iSetter != null ? iSetter.Name : "set_" + prop.Name;
|
|
|
|
accessor &= ~MethodAttributes.Abstract;
|
|
|
|
var methBuilder = typeBuilder.DefineMethod(name, accessor, typeof(void), new[] { propType });
|
|
var il = methBuilder.GetILGenerator();
|
|
|
|
if (iGetter != null)
|
|
{
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldarg_1);
|
|
il.Emit(OpCodes.Stfld, getBackingField());
|
|
il.Emit(OpCodes.Ret);
|
|
}
|
|
else
|
|
{
|
|
il.Emit(OpCodes.Ret);
|
|
}
|
|
|
|
propBuilder.SetSetMethod(methBuilder);
|
|
}
|
|
}
|
|
|
|
foreach (var method in allMembers.OfType<MethodInfo>().Except(propertyInfos))
|
|
{
|
|
var methBuilder = typeBuilder.DefineMethod(method.Name, MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, method.ReturnType, method.GetParameters().Select(e => e.ParameterType).ToArray());
|
|
if (method.IsGenericMethod)
|
|
{
|
|
methBuilder.DefineGenericParameters(method.GetGenericArguments().Select(e => e.Name).ToArray());
|
|
}
|
|
var il = methBuilder.GetILGenerator();
|
|
il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructors()[0]);
|
|
il.Emit(OpCodes.Throw);
|
|
|
|
typeBuilder.DefineMethodOverride(methBuilder, method);
|
|
}
|
|
|
|
var proxyInfo = typeBuilder.CreateTypeInfo();
|
|
|
|
Proxy = proxyInfo.AsType();
|
|
|
|
AssemblyBuilderContainer.TypeNames.Add(className);
|
|
}
|
|
catch (TypeLoadException)
|
|
{
|
|
throw new JsonNoSupportedDeserializeTypeException(typeof(TInterface), "Interface access properties must be public");
|
|
}
|
|
catch {
|
|
throw new JsonNoSupportedDeserializeTypeException(typeof(TInterface));
|
|
}
|
|
}
|
|
|
|
static Type ReturnType(MemberInfo m)
|
|
{
|
|
var asField = m as FieldInfo;
|
|
var asProp = m as PropertyInfo;
|
|
return
|
|
asField != null ? asField.FieldType : asProp.PropertyType;
|
|
}
|
|
}
|
|
|
|
static class AssemblyBuilderContainer
|
|
{
|
|
private static readonly AssemblyBuilder AsmBuilder;
|
|
|
|
internal static readonly ModuleBuilder ModBuilder;
|
|
|
|
internal static List<string> TypeNames = new List<string>();
|
|
|
|
static AssemblyBuilderContainer()
|
|
{
|
|
AsmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("KoobooInterfaceTypeProxies"), AssemblyBuilderAccess.Run);
|
|
ModBuilder = AsmBuilder.DefineDynamicModule("InterfaceProxies");
|
|
}
|
|
}
|
|
|
|
|
|
}
|