Mercurial > pub > bltoolkit
diff Source/TypeBuilder/Builders/ImplementInterfaceBuilder.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/TypeBuilder/Builders/ImplementInterfaceBuilder.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,212 @@ +using System; +using System.Reflection.Emit; + +namespace BLToolkit.TypeBuilder.Builders +{ + using Reflection; + + class ImplementInterfaceBuilder : AbstractTypeBuilderBase + { + public ImplementInterfaceBuilder(Type type) + { + _type = type; + } + + private readonly Type _type; + + public override Type[] GetInterfaces() + { + return new[] { _type }; + } + + public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) + { + if (context == null) throw new ArgumentNullException("context"); + + return context.BuildElement == BuildElement.InterfaceMethod; + } + + protected override void BuildInterfaceMethod() + { + var returnIfNonZero = false; + var returnIfZero = false; + + if (Context.ReturnValue != null) + { + var attrs = Context.MethodBuilder.OverriddenMethod.ReturnTypeCustomAttributes.GetCustomAttributes(true); + + foreach (var o in attrs) + { + if (o is ReturnIfNonZeroAttribute) returnIfNonZero = true; + else if (o is ReturnIfZeroAttribute) returnIfZero = true; + } + } + + var interfaceType = Context.CurrentInterface; + var emit = Context.MethodBuilder.Emitter; + + foreach (var de in Context.Fields) + { + var property = de.Key; + var field = de.Value; + + if (field.FieldType.IsPrimitive || field.FieldType == typeof(string)) + continue; + + var types = field.FieldType.GetInterfaces(); + + foreach (var type in types) + { + if (type != interfaceType.Type) + continue; + + var im = field.FieldType.GetInterfaceMap(type); + + for (var j = 0; j < im.InterfaceMethods.Length; j++) + { + if (im.InterfaceMethods[j] == Context.MethodBuilder.OverriddenMethod) + { + var targetMethod = im.TargetMethods[j]; + + var label = new Label(); + var checkNull = false; + + if (CallLazyInstanceInsurer(field) == false && field.FieldType.IsClass) + { + // Check if field is null. + // + checkNull = true; + + label = emit.DefineLabel(); + + emit + .ldarg_0 + .ldfld (field) + .brfalse_s (label) + ; + } + + // this. + // + emit + .ldarg_0 + .end(); + + // Load the field and prepare it for interface method call if the method is private. + // + if (field.FieldType.IsValueType) + { + if (targetMethod.IsPublic) + emit.ldflda (field); + else + emit + .ldfld (field) + .box (field.FieldType); + } + else + { + if (targetMethod.IsPublic) + emit.ldfld (field); + else + emit + .ldfld (field) + .castclass (interfaceType); + } + + // Check parameter attributes. + // + var pi = Context.MethodBuilder.OverriddenMethod.GetParameters(); + + for (var k = 0; k < pi.Length; k++) + { + var attrs = pi[k].GetCustomAttributes(true); + var stop = false; + + foreach (var a in attrs) + { + // Parent - set this. + // + if (a is ParentAttribute) + { + emit + .ldarg_0 + .end() + ; + + if (!TypeHelper.IsSameOrParent(pi[k].ParameterType, Context.Type)) + emit + .castclass (pi[k].ParameterType) + ; + + stop = true; + + break; + } + + // PropertyInfo. + // + if (a is PropertyInfoAttribute) + { + var ifb = GetPropertyInfoField(property); + + emit.ldsfld(ifb); + stop = true; + + break; + } + } + + if (stop) + continue; + + // Pass argument. + // + emit.ldarg ((byte)(k + 1)); + } + + // Call the method. + // + if (field.FieldType.IsValueType) + { + if (targetMethod.IsPublic) emit.call (targetMethod); + else emit.callvirt (im.InterfaceMethods[j]); + } + else + { + if (targetMethod.IsPublic) emit.callvirt (targetMethod); + else emit.callvirt (im.InterfaceMethods[j]); + } + + // Return if appropriated result. + // + if (Context.ReturnValue != null) + { + emit.stloc(Context.ReturnValue); + + if (returnIfNonZero) + { + emit + .ldloc (Context.ReturnValue) + .brtrue (Context.ReturnLabel); + } + else if (returnIfZero) + { + emit + .ldloc (Context.ReturnValue) + .brfalse (Context.ReturnLabel); + } + } + + if (checkNull) + emit.MarkLabel(label); + + break; + } + } + + break; + } + } + } + } +}