Remove the converter logic
This commit is contained in:
parent
28fbacc7f4
commit
e3afbae213
|
|
@ -3,7 +3,6 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNet.FeatureModel.Implementation;
|
||||
|
||||
namespace Microsoft.AspNet.FeatureModel
|
||||
{
|
||||
|
|
@ -49,11 +48,8 @@ namespace Microsoft.AspNet.FeatureModel
|
|||
{
|
||||
return feature;
|
||||
}
|
||||
#if NET45
|
||||
return Converter.Convert(type, actualType, feature);
|
||||
#else
|
||||
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.FeatureModel.Implementation;
|
||||
|
||||
namespace Microsoft.AspNet.FeatureModel
|
||||
{
|
||||
|
|
@ -32,20 +31,6 @@ namespace Microsoft.AspNet.FeatureModel
|
|||
return _instance;
|
||||
}
|
||||
|
||||
#if NET45
|
||||
foreach (var interfaceType in _instance.GetType().GetInterfaces())
|
||||
{
|
||||
if (interfaceType.FullName == type.FullName)
|
||||
{
|
||||
return Converter.Convert(interfaceType, type, _instance);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (_instance != null && type == _instance.GetType())
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,388 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
#if NET45
|
||||
using System.Reflection.Emit;
|
||||
#endif
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.AspNet.FeatureModel.Implementation
|
||||
{
|
||||
#if NET45
|
||||
public abstract class NonGenericProxyBase
|
||||
{
|
||||
public readonly Type WrappedType;
|
||||
protected NonGenericProxyBase(Type wrappedType)
|
||||
{
|
||||
this.WrappedType = wrappedType;
|
||||
}
|
||||
public abstract object UnderlyingInstanceAsObject
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseType<T> : NonGenericProxyBase where T : class
|
||||
{
|
||||
protected T instance;
|
||||
public BaseType(T inst)
|
||||
: base(typeof(T))
|
||||
{
|
||||
if (inst == null) throw new InvalidOperationException("should never construct proxy over null");
|
||||
this.instance = inst;
|
||||
}
|
||||
public T UnderlyingInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
public override object UnderlyingInstanceAsObject
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Converter
|
||||
{
|
||||
public static object Convert(Type outputType, Type inputType, object input)
|
||||
{
|
||||
if (inputType == outputType) return input;
|
||||
|
||||
if (!inputType.IsInterface || !outputType.IsInterface) throw new InvalidOperationException("Both types must be interfaces");
|
||||
|
||||
if (inputType.GetInterfaces().Contains(outputType)) return input;
|
||||
|
||||
if (input == null) return null;
|
||||
|
||||
Type t = EnsureConverter(outputType, inputType);
|
||||
|
||||
return Activator.CreateInstance(t, input);
|
||||
}
|
||||
|
||||
public static TOut Convert<TOut>(Type inputType, object input)
|
||||
where TOut : class
|
||||
{
|
||||
return (TOut)Convert(typeof (TOut), inputType, input);
|
||||
}
|
||||
|
||||
public static TOut Convert<TIn, TOut>(TIn input)
|
||||
where TIn : class
|
||||
where TOut : class
|
||||
{
|
||||
return Convert<TOut>(typeof(TIn), input);
|
||||
}
|
||||
|
||||
public static TOut Convert<TOut>(object input)
|
||||
where TOut : class
|
||||
{
|
||||
if (input == null) return null;
|
||||
var interfaceName = typeof(TOut).FullName;
|
||||
foreach (var inputType in input.GetType().GetInterfaces())
|
||||
{
|
||||
if (inputType.FullName == interfaceName)
|
||||
{
|
||||
return Convert<TOut>(inputType, input);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Type EnsureConverter(Type tout, Type tin)
|
||||
{
|
||||
CacheResult result;
|
||||
if (!ConverterTypeCache.TryGetValue(new Tuple<Type, Type>(tin, tout), out result))
|
||||
{
|
||||
EnsureCastPossible(tout, tin);
|
||||
return EnsureConverter(tout, tin);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result is ErrorResult)
|
||||
{
|
||||
throw new InvalidCastException((result as ErrorResult).error);
|
||||
}
|
||||
else if (result is CurrentlyVerifyingResult)
|
||||
{
|
||||
throw new InvalidOperationException("Type cannot be obtained in verification phase");
|
||||
}
|
||||
else if (result is TypeBuilderResult)
|
||||
{
|
||||
return (result as TypeBuilderResult).result;
|
||||
}
|
||||
else if (result is VerificationSucceededResult)
|
||||
{
|
||||
return CreateWrapperType(tout, tin, result as VerificationSucceededResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Invalid cache state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CacheResult
|
||||
{
|
||||
}
|
||||
|
||||
class TypeBuilderResult : CacheResult
|
||||
{
|
||||
internal TypeBuilderResult(Type result)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
internal readonly Type result;
|
||||
}
|
||||
class ErrorResult : CacheResult
|
||||
{
|
||||
internal ErrorResult(string error)
|
||||
{
|
||||
this.error = error;
|
||||
}
|
||||
internal readonly string error;
|
||||
}
|
||||
class CurrentlyVerifyingResult : CacheResult
|
||||
{
|
||||
}
|
||||
enum SuccessKind
|
||||
{
|
||||
Identity,
|
||||
SubInterface,
|
||||
Wrapper,
|
||||
}
|
||||
class VerificationSucceededResult : CacheResult
|
||||
{
|
||||
internal VerificationSucceededResult(SuccessKind kind)
|
||||
{
|
||||
this.kind = kind;
|
||||
}
|
||||
internal VerificationSucceededResult(Dictionary<MethodInfo, MethodInfo> mappings)
|
||||
{
|
||||
this.kind = SuccessKind.Wrapper;
|
||||
this.methodMappings = mappings;
|
||||
}
|
||||
internal readonly SuccessKind kind;
|
||||
internal readonly Dictionary<MethodInfo, MethodInfo> methodMappings;
|
||||
}
|
||||
|
||||
static Dictionary<Tuple<Type, Type>, CacheResult> ConverterTypeCache = new Dictionary<Tuple<Type, Type>, CacheResult>();
|
||||
static ConditionalWeakTable<object, NonGenericProxyBase> ConverterInstanceCache = new ConditionalWeakTable<object, NonGenericProxyBase>();
|
||||
static AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("ProxyHolderAssembly"), AssemblyBuilderAccess.Run);
|
||||
static ModuleBuilder modb = ab.DefineDynamicModule("Main Module");
|
||||
|
||||
class EqComparer : IEqualityComparer<ParameterInfo>
|
||||
{
|
||||
|
||||
bool IEqualityComparer<ParameterInfo>.Equals(ParameterInfo x, ParameterInfo y)
|
||||
{
|
||||
return EqualTypes(x.ParameterType, y.ParameterType);
|
||||
}
|
||||
|
||||
int IEqualityComparer<ParameterInfo>.GetHashCode(ParameterInfo obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static bool EqualTypes(Type sourceType, Type targetType)
|
||||
{
|
||||
return EnsureCastPossible(targetType, sourceType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static MethodInfo FindCorrespondingMethod(Type targetType, Type sourceType, MethodInfo miTarget)
|
||||
{
|
||||
MethodInfo[] sms = sourceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where((MethodInfo mi) => mi.Name == miTarget.Name).ToArray();
|
||||
if (sms != null && sms.Length != 0)
|
||||
{
|
||||
MethodInfo[] sm = null;
|
||||
try
|
||||
{
|
||||
sm = sms.Where((mi) => (mi.GetParameters().SequenceEqual(miTarget.GetParameters(), new EqComparer()))).ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
if (sm != null && sm.Length != 0)
|
||||
{
|
||||
if (sm.Length > 1) return null;
|
||||
if (EqualTypes(sm[0].ReturnType, miTarget.ReturnType))
|
||||
{
|
||||
return sm[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
MethodInfo[] rval = sourceType.GetInterfaces().Select((inheritedItf) => FindCorrespondingMethod(targetType, inheritedItf, miTarget)).ToArray();
|
||||
if (rval == null || rval.Length == 0) return null;
|
||||
if (rval.Length > 1) return null;
|
||||
return rval[0];
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void AddMethod(Type targetType, Type sourceType, TypeBuilder tb, MethodInfo miTarget, MethodInfo miSource)
|
||||
{
|
||||
ParameterInfo[] pisTarget = miTarget.GetParameters();
|
||||
ParameterInfo[] pisSource = miSource.GetParameters();
|
||||
MethodBuilder metb;
|
||||
Type[] typesTarget;
|
||||
if (pisTarget == null || pisTarget.Length == 0)
|
||||
{
|
||||
metb = tb.DefineMethod(miTarget.Name, MethodAttributes.Virtual, CallingConventions.HasThis, miTarget.ReturnType, null);
|
||||
pisTarget = new ParameterInfo[0];
|
||||
typesTarget = new Type[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
typesTarget = pisTarget.Select((pi) => pi.ParameterType).ToArray();
|
||||
Type[][] requiredCustomMods = pisTarget.Select((pi) => pi.GetRequiredCustomModifiers()).ToArray();
|
||||
Type[][] optionalCustomMods = pisTarget.Select((pi) => pi.GetOptionalCustomModifiers()).ToArray();
|
||||
|
||||
metb = tb.DefineMethod(miTarget.Name, MethodAttributes.Virtual, CallingConventions.HasThis, miTarget.ReturnType, null, null, typesTarget, requiredCustomMods, optionalCustomMods);
|
||||
}
|
||||
|
||||
ILGenerator il = metb.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Ldfld, tb.BaseType.GetField("instance", BindingFlags.NonPublic | BindingFlags.Instance));
|
||||
for (int pi = 0; pi < pisTarget.Length; pi++)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg, pi + 1);
|
||||
EmitParamConversion(il, typesTarget[pi], pisSource[pi].ParameterType);
|
||||
}
|
||||
il.EmitCall(OpCodes.Callvirt, miSource, null);
|
||||
|
||||
EmitParamConversion(il, miSource.ReturnType, miTarget.ReturnType);
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
tb.DefineMethodOverride(metb, miTarget);
|
||||
}
|
||||
|
||||
static void EmitParamConversion(ILGenerator il, Type typeOnStack, Type typeRequiredInSignature)
|
||||
{
|
||||
if (typeOnStack != typeRequiredInSignature)
|
||||
{
|
||||
if (typeOnStack.GetInterfaces().Contains(typeRequiredInSignature))
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, typeRequiredInSignature);
|
||||
}
|
||||
else
|
||||
{
|
||||
Label lEnd = il.DefineLabel();
|
||||
Label lCreateProxy = il.DefineLabel();
|
||||
il.Emit(OpCodes.Dup); // o o
|
||||
il.Emit(OpCodes.Brfalse_S, lEnd); // o
|
||||
il.Emit(OpCodes.Dup); // o o
|
||||
il.Emit(OpCodes.Isinst, typeof(NonGenericProxyBase)); // o [p/n]
|
||||
il.Emit(OpCodes.Brfalse_S, lCreateProxy); // o
|
||||
il.Emit(OpCodes.Isinst, typeof(NonGenericProxyBase)); // p
|
||||
il.EmitCall(OpCodes.Callvirt, typeof(NonGenericProxyBase).GetMethod("get_UnderlyingInstanceAsObject"), null); // uo
|
||||
il.Emit(OpCodes.Dup); // uo uo
|
||||
il.Emit(OpCodes.Isinst, typeRequiredInSignature); // uo [ro/n]
|
||||
il.Emit(OpCodes.Brtrue_S, lEnd); // uo
|
||||
il.MarkLabel(lCreateProxy); // uo
|
||||
Type paramProxyType = EnsureConverter(typeRequiredInSignature, typeOnStack);
|
||||
il.Emit(OpCodes.Newobj, paramProxyType.GetConstructors()[0]);
|
||||
il.MarkLabel(lEnd); // ro
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool EnsureCastPossible(Type targetType, Type sourceType)
|
||||
{
|
||||
var key = new Tuple<Type, Type>(sourceType, targetType);
|
||||
CacheResult cr = null;
|
||||
if (ConverterTypeCache.TryGetValue(key, out cr))
|
||||
{
|
||||
if (cr is CurrentlyVerifyingResult || cr is VerificationSucceededResult || cr is TypeBuilderResult) return true;
|
||||
if (cr is ErrorResult) return false;
|
||||
}
|
||||
if (targetType == sourceType)
|
||||
{
|
||||
ConverterTypeCache[key] = new VerificationSucceededResult(SuccessKind.Identity);
|
||||
return true;
|
||||
}
|
||||
if (targetType.GetInterfaces().Contains(sourceType))
|
||||
{
|
||||
ConverterTypeCache[key] = new VerificationSucceededResult(SuccessKind.SubInterface);
|
||||
return true;
|
||||
}
|
||||
if (!targetType.IsInterface || !sourceType.IsInterface)
|
||||
{
|
||||
ConverterTypeCache[key] = new ErrorResult("Cannot cast " + sourceType + " to " + targetType);
|
||||
return false;
|
||||
}
|
||||
bool success = false;
|
||||
ConverterTypeCache[key] = new CurrentlyVerifyingResult();
|
||||
try
|
||||
{
|
||||
Dictionary<MethodInfo, MethodInfo> mappings = new Dictionary<MethodInfo, MethodInfo>();
|
||||
foreach (MethodInfo mi in targetType.GetMethods().Concat(targetType.GetInterfaces().SelectMany((itf) => itf.GetMethods())))
|
||||
{
|
||||
MethodInfo mapping = FindCorrespondingMethod(targetType, sourceType, mi);
|
||||
if (mapping == null)
|
||||
{
|
||||
ConverterTypeCache[key] = new ErrorResult("Can not cast " + sourceType + " to " + targetType + " because of missing method: " + mi.Name);
|
||||
return false;
|
||||
}
|
||||
mappings[mi] = mapping;
|
||||
}
|
||||
ConverterTypeCache[key] = new VerificationSucceededResult(mappings);
|
||||
success = true;
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
if (!(ConverterTypeCache[key] is ErrorResult))
|
||||
{
|
||||
ConverterTypeCache[key] = new ErrorResult("Can not cast " + sourceType + " to " + targetType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int counter = 0;
|
||||
static Type CreateWrapperType(Type targetType, Type sourceType, VerificationSucceededResult result)
|
||||
{
|
||||
Dictionary<MethodInfo, MethodInfo> mappings = result.methodMappings;
|
||||
Type baseType = typeof(BaseType<>).MakeGenericType(sourceType);
|
||||
TypeBuilder tb = modb.DefineType("ProxyType" + counter++ + " wrapping:" + sourceType.Name + " to look like:" + targetType.Name, TypeAttributes.Class, baseType, new Type[] { targetType });
|
||||
ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { sourceType });
|
||||
ILGenerator il = cb.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
il.Emit(OpCodes.Castclass, sourceType);
|
||||
il.Emit(OpCodes.Call, baseType.GetConstructor(new Type[] { sourceType }));
|
||||
il.Emit(OpCodes.Ret);
|
||||
var tuple = new Tuple<Type, Type>(sourceType, targetType);
|
||||
try
|
||||
{
|
||||
ConverterTypeCache[tuple] = new TypeBuilderResult(tb);
|
||||
foreach (MethodInfo mi in targetType.GetMethods().Concat(targetType.GetInterfaces().SelectMany((itf) => itf.GetMethods())))
|
||||
{
|
||||
AddMethod(targetType, sourceType, tb, mi, mappings[mi]);
|
||||
}
|
||||
Type t = tb.CreateType();
|
||||
ConverterTypeCache[tuple] = new TypeBuilderResult(t);
|
||||
return t;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ConverterTypeCache[tuple] = new ErrorResult(e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@
|
|||
<Compile Include="FeatureCollection.cs" />
|
||||
<Compile Include="FeatureObject.cs" />
|
||||
<Compile Include="IFeatureCollection.cs" />
|
||||
<Compile Include="Implementation\Converter.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\ProjectK\Microsoft.Web.ProjectK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
Loading…
Reference in New Issue