Permalink
Browse files

Added recursive interfaces when actinglike. Still need attributes to …

…override

this behavoir.
  • Loading branch information...
1 parent 48aba94 commit c7a026ecfafda62e928c3c07ff310eb072b00246 jayt committed Jul 24, 2012
@@ -47,6 +47,15 @@ public static class BuildProxy
private static readonly IDictionary<TypeHash, Type> _delegateCache = new Dictionary<TypeHash, Type>();
private static readonly object DelegateCacheLock = new object();
+ private static readonly MethodInfo ActLike = typeof(BuildProxy).GetMethod("SimpleActLike",
+ new[] {typeof(object)});
+
+ public static TInterface SimpleActLike<TInterface>(object target) where TInterface:class
+ {
+ return target.ActLike<TInterface>();
+ }
+
+
#if !SILVERLIGHT
internal class TempBuilder : IDisposable
{
@@ -701,7 +710,7 @@ MethodEmitInfo emitInfo
tIlGen.Emit(OpCodes.Stsfld, tInvokeField);
}
- if (emitInfo.ResolveReturnType != typeof(void))
+ if (emitInfo.ResolveReturnType != typeof(void) && !emitInfo.ResolveReturnType.IsInterface)
{
tIlGen.Emit(OpCodes.Ldsfld, tConvertField);
tIlGen.Emit(OpCodes.Ldfld, typeof(CallSite<>).MakeGenericType(emitInfo.CallSiteConvertFuncType).GetFieldEvenIfGeneric("Target"));
@@ -719,11 +728,35 @@ MethodEmitInfo emitInfo
tIlGen.EmitLoadArgument(i);
}
tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteInvokeFuncType);
- if (emitInfo.ResolveReturnType != typeof(void))
+ if (emitInfo.ResolveReturnType != typeof(void) && !emitInfo.ResolveReturnType.IsInterface)
+ {
+ tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteConvertFuncType);
+ }
+
+ //If return type is interface and instance is not interface, try actlike
+ if (emitInfo.ResolveReturnType.IsInterface)
{
+ var tReturnLocal = tIlGen.DeclareLocal(typeof(object));
+ tIlGen.EmitStoreLocation(tReturnLocal.LocalIndex);
+ using (tIlGen.EmitBranchFalse(gen => gen.EmitLoadLocation(tReturnLocal.LocalIndex)))
+ {
+ tIlGen.EmitLoadLocation(tReturnLocal.LocalIndex);
+ using (tIlGen.EmitBranchTrue(gen => gen.Emit(OpCodes.Isinst, emitInfo.ResolveReturnType)))
+ {
+ tIlGen.EmitLoadLocation(tReturnLocal.LocalIndex);
+ tIlGen.Emit(OpCodes.Call, ActLike.MakeGenericMethod(emitInfo.ResolveReturnType));
+ tIlGen.Emit(OpCodes.Ret);
+ }
+ }
+
+ tIlGen.Emit(OpCodes.Ldsfld, tConvertField);
+ tIlGen.Emit(OpCodes.Ldfld, typeof(CallSite<>).MakeGenericType(emitInfo.CallSiteConvertFuncType).GetFieldEvenIfGeneric("Target"));
+ tIlGen.Emit(OpCodes.Ldsfld, tConvertField);
+ tIlGen.EmitLoadLocation(tReturnLocal.LocalIndex);
tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteConvertFuncType);
}
+
tIlGen.Emit(OpCodes.Ret);
}
@@ -1282,7 +1315,10 @@ PropertyEmitInfo emitInfo
var tIlGen = getMethodBuilder.GetILGenerator();
var tConvertCallsiteField = emitInfo.CallSiteType.GetFieldEvenIfGeneric(emitInfo.CallSiteConvertName);
- var tReturnLocal = tIlGen.DeclareLocal(emitInfo.ResolveReturnType);
+
+ //If we want to do recursive Interfaces we need to test the interface before we dynamically cast
+ var tReturnLocal = tIlGen.DeclareLocal(emitInfo.ResolveReturnType.IsInterface? typeof(object) : emitInfo.ResolveReturnType);
+
using (tIlGen.EmitBranchTrue(gen => gen.Emit(OpCodes.Ldsfld, tConvertCallsiteField)))
{
@@ -1301,9 +1337,13 @@ PropertyEmitInfo emitInfo
}
- tIlGen.Emit(OpCodes.Ldsfld, tConvertCallsiteField);
- tIlGen.Emit(OpCodes.Ldfld, tConvertCallsiteField.FieldType.GetFieldEvenIfGeneric("Target"));
- tIlGen.Emit(OpCodes.Ldsfld, tConvertCallsiteField);
+ //If it's an interface we do this later.
+ if (!emitInfo.ResolveReturnType.IsInterface)
+ {
+ tIlGen.Emit(OpCodes.Ldsfld, tConvertCallsiteField);
+ tIlGen.Emit(OpCodes.Ldfld, tConvertCallsiteField.FieldType.GetFieldEvenIfGeneric("Target"));
+ tIlGen.Emit(OpCodes.Ldsfld, tConvertCallsiteField);
+ }
tIlGen.Emit(OpCodes.Ldsfld, tInvokeGetCallsiteField);
tIlGen.Emit(OpCodes.Ldfld, tInvokeGetCallsiteField.FieldType.GetFieldEvenIfGeneric("Target"));
tIlGen.Emit(OpCodes.Ldsfld, tInvokeGetCallsiteField);
@@ -1314,12 +1354,46 @@ PropertyEmitInfo emitInfo
tIlGen.EmitLoadArgument(i);
}
tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteInvokeGetFuncType);
- tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteConvertFuncType);
+
+ //If it's an interface we do this later.
+ if (!emitInfo.ResolveReturnType.IsInterface)
+ {
+ tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteConvertFuncType);
+ }
+
tIlGen.EmitStoreLocation(tReturnLocal.LocalIndex);
+
+
+ //If return type is interface and instance is not interface, try actlike
+ if (emitInfo.ResolveReturnType.IsInterface)
+ {
+ using (tIlGen.EmitBranchFalse(gen => gen.EmitLoadLocation(tReturnLocal.LocalIndex)))
+ {
+ tIlGen.EmitLoadLocation(tReturnLocal.LocalIndex);
+ using (tIlGen.EmitBranchTrue(gen => gen.Emit(OpCodes.Isinst, emitInfo.ResolveReturnType)))
+ {
+ tIlGen.EmitLoadLocation(tReturnLocal.LocalIndex);
+ tIlGen.Emit(OpCodes.Call, ActLike.MakeGenericMethod(emitInfo.ResolveReturnType));
+ tIlGen.Emit(OpCodes.Ret);
+ }
+ }
+ }
+
var tReturnLabel =tIlGen.DefineLabel();
tIlGen.Emit(OpCodes.Br_S, tReturnLabel);
tIlGen.MarkLabel(tReturnLabel);
+ if (emitInfo.ResolveReturnType.IsInterface)
+ {
+ tIlGen.Emit(OpCodes.Ldsfld, tConvertCallsiteField);
+ tIlGen.Emit(OpCodes.Ldfld, tConvertCallsiteField.FieldType.GetFieldEvenIfGeneric("Target"));
+ tIlGen.Emit(OpCodes.Ldsfld, tConvertCallsiteField);
+ }
tIlGen.EmitLoadLocation(tReturnLocal.LocalIndex);
+ if (emitInfo.ResolveReturnType.IsInterface)
+ {
+ tIlGen.EmitCallInvokeFunc(emitInfo.CallSiteConvertFuncType);
+ }
+
tIlGen.Emit(OpCodes.Ret);
tMp.SetGetMethod(getMethodBuilder);
@@ -60,6 +60,31 @@ public void Dispose()
}
}
+ public class BranchFalseOverBlock : IDisposable
+ {
+ private readonly ILGenerator _generator;
+ private readonly Label _label;
+
+ ///<summary>
+ /// Constructor
+ ///</summary>
+ ///<param name="generator"></param>
+ public BranchFalseOverBlock(ILGenerator generator)
+ {
+ _generator = generator;
+ _label = generator.DefineLabel();
+ _generator.Emit(OpCodes.Brfalse, _label);
+ }
+
+ /// <summary>
+ /// Finishes block
+ /// </summary>
+ public void Dispose()
+ {
+ //_generator.Emit(OpCodes.Br_S, _label);
+ _generator.MarkLabel(_label);
+ }
+ }
/// <summary>
/// Gets the field info even if generic type parameter.
/// </summary>
@@ -154,6 +179,12 @@ public static BranchTrueOverBlock EmitBranchTrue(this ILGenerator generator, Act
return new BranchTrueOverBlock(generator);
}
+ public static BranchFalseOverBlock EmitBranchFalse(this ILGenerator generator, Action<ILGenerator> condition)
+ {
+ condition(generator);
+ return new BranchFalseOverBlock(generator);
+ }
+
/// <summary>
/// Emits the call.
/// </summary>
@@ -152,6 +152,37 @@ public void DoubleInterfacetest()
Assert.AreEqual(tNew.ReturnProp, tActsLike.ReturnProp);
}
+ [Test]
+ public void NestedInterfacetest()
+ {
+ dynamic tNew = new ExpandoObject();
+ tNew.NameLevel1 = "one";
+ tNew.Nested = new ExpandoObject();
+ tNew.Nested.NameLevel2 = "two";
+
+ INest tActsLike = Impromptu.ActLike<INest>(tNew);
+
+ Assert.AreEqual(tNew.NameLevel1, tActsLike.NameLevel1);
+ Assert.AreEqual(tNew.Nested.NameLevel2, tActsLike.Nested.NameLevel2);
+
+ }
+
+ [Test]
+ public void NestedInterfaceMethodtest()
+ {
+ dynamic tNew = new ExpandoObject();
+ dynamic tNew2 = new ExpandoObject();
+ tNew.NameLevel1 = "one";
+ tNew.Nested = new Func<object, object, object>((x, y) => tNew2);
+ tNew.Nested(1, 2).NameLevel2 = "two";
+
+ INestMeth tActsLike = Impromptu.ActLike<INestMeth>(tNew);
+
+ Assert.AreEqual(tNew.NameLevel1, tActsLike.NameLevel1);
+ Assert.AreEqual(tNew.Nested(1,2).NameLevel2, tActsLike.Nested(1,2).NameLevel2);
+
+ }
+
[Test]
public void DoublePropertyTest()
{
@@ -401,8 +401,14 @@ public interface INest
{
String NameLevel1 {get;set;}
INested Nested {get;set;}
- }
-
+ }
+
+ public interface INestMeth
+ {
+ String NameLevel1 { get; set; }
+ INested Nested(object one, object two);
+ }
+
public interface INested
{
string NameLevel2 {get;}

0 comments on commit c7a026e

Please sign in to comment.