Example #1
0
		public Type Build(AssemblyBuilderHelper assemblyBuilder)
		{
			if (assemblyBuilder == null) throw new ArgumentNullException("assemblyBuilder");

			// Check InternalsVisibleToAttributes of the source type's assembly.
			// Even if the sourceType is public, it may have internal fields and props.
			//
			_friendlyAssembly = false;

			// Usually, there is no such attribute in the source assembly.
			// Therefore we do not cache the result.
			//
			var attributes = _originalType.Type.Assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), true);

			foreach (InternalsVisibleToAttribute visibleToAttribute in attributes)
			{
				var an = new AssemblyName(visibleToAttribute.AssemblyName);

				if (AssemblyName.ReferenceMatchesDefinition(assemblyBuilder.AssemblyName, an))
				{
					_friendlyAssembly = true;
					break;
				}
			}

			if (!_originalType.Type.IsVisible && !_friendlyAssembly)
				return typeof (ExprTypeAccessor<,>).MakeGenericType(_type, _originalType);

			var typeName = GetTypeName();

			_typeBuilder = assemblyBuilder.DefineType(typeName, _accessorType);

			_typeBuilder.DefaultConstructor.Emitter
				.ldarg_0
				.call    (TypeHelper.GetDefaultConstructor(_accessorType))
				;

			BuildCreateInstanceMethods();
			BuildTypeProperties();
			BuildMembers();
			BuildObjectFactory();

			_typeBuilder.DefaultConstructor.Emitter
				.ret()
				;

			var result = _typeBuilder.Create();

			foreach (TypeBuilderHelper tb in _nestedTypes)
				tb.Create();

			return result;
		}
		private static ConstructorBuilderHelper BuildNestedTypeConstructor(TypeBuilderHelper nestedType)
		{
			Type[] parameters = { typeof(TypeAccessor), typeof(MemberInfo) };

			var ctorBuilder = nestedType.DefinePublicConstructor(parameters);

			ctorBuilder.Emitter
				.ldarg_0
				.ldarg_1
				.ldarg_2
				.call    (TypeHelper.GetConstructor(typeof(MemberAccessor), parameters))
				.ret()
				;

			return ctorBuilder;
		}
		private void BuildTypedSetterForNullable(
			MemberInfo        mi,
			TypeBuilderHelper nestedType,
			Type              memberType)
		{
			var methodType = mi.DeclaringType;
			var setMethod  = null as MethodInfo;

			if (mi is PropertyInfo)
			{
				setMethod = ((PropertyInfo)mi).GetSetMethod();

				if (setMethod == null)
				{
					if (_type != _originalType)
					{
						setMethod  = _type.GetMethod("set_" + mi.Name);
						methodType = _type;
					}

					if (setMethod == null || !IsMethodAccessible(setMethod))
						return;
				}
			}

			var setterType = (memberType.IsEnum ? Enum.GetUnderlyingType(memberType) : memberType);
			var methodInfo = _memberAccessor.GetMethod("Set" + setterType.Name, typeof(object), setterType);

			if (methodInfo == null)
				return;

			var method = nestedType.DefineMethod(methodInfo);
			var emit   = method.Emitter;

			emit
				.ldarg_1
				.castType (methodType)
				.ldarg_2
				.newobj   (typeof(Nullable<>).MakeGenericType(memberType), memberType)
				.end();

			if (mi is FieldInfo) emit.stfld   ((FieldInfo)mi);
			else                 emit.callvirt(setMethod);

			emit
				.ret()
				;
		}
		private void BuildTypedGetterForNullable(
			MemberInfo        mi,
			TypeBuilderHelper nestedType,
			Type              memberType)
		{
			var methodType = mi.DeclaringType;
			var getMethod  = null as MethodInfo;

			if (mi is PropertyInfo)
			{
				getMethod = ((PropertyInfo)mi).GetGetMethod();

				if (getMethod == null)
				{
					if (_type != _originalType)
					{
						getMethod  = _type.GetMethod("get_" + mi.Name);
						methodType = _type;
					}

					if (getMethod == null || !IsMethodAccessible(getMethod))
						return;
				}
			}

			var setterType = (memberType.IsEnum ? Enum.GetUnderlyingType(memberType) : memberType);
			var methodInfo = _memberAccessor.GetMethod("Get" + setterType.Name, typeof(object));

			if (methodInfo == null)
				return;

			var method       = nestedType.DefineMethod(methodInfo);
			var nullableType = typeof(Nullable<>).MakeGenericType(memberType);
			var emit         = method.Emitter;

			emit
				.ldarg_1
				.castType (methodType)
				.end();

			if (mi is FieldInfo)
			{
				emit.ldflda  ((FieldInfo)mi);
			}
			else
			{
				var locNullable = emit.DeclareLocal(nullableType);

				emit
					.callvirt (getMethod)
					.stloc    (locNullable)
					.ldloca   (locNullable)
					;
			}

			emit
				.call(nullableType, "get_Value")
				.ret()
				;
		}
		private void BuildCloneValueMethod(
			MemberInfo        mi,
			TypeBuilderHelper nestedType,
			Type              memberType
			)
		{
			var methodType = mi.DeclaringType;
			var getMethod  = null as MethodInfo;
			var setMethod  = null as MethodInfo;

			if (mi is PropertyInfo)
			{
				getMethod = ((PropertyInfo)mi).GetGetMethod();

				if (getMethod == null)
				{
					if (_type != _originalType)
					{
						getMethod  = _type.GetMethod("get_" + mi.Name);
						methodType = _type;
					}

					if (getMethod == null || !IsMethodAccessible(getMethod))
						return;
				}

				setMethod = ((PropertyInfo)mi).GetSetMethod();

				if (setMethod == null)
				{
					if (_type != _originalType)
					{
						setMethod  = _type.GetMethod("set_" + mi.Name);
						methodType = _type;
					}

					if (setMethod == null || !IsMethodAccessible(setMethod))
						return;
				}
			}

			var method = nestedType.DefineMethod(_memberAccessor.GetMethod("CloneValue", typeof(object), typeof(object)));
			var emit   = method.Emitter;

			emit
				.ldarg_2
				.castType (methodType)
				.ldarg_1
				.castType (methodType)
				.end();

			if (mi is FieldInfo)
				emit.ldfld   ((FieldInfo)mi);
			else
				emit.callvirt(getMethod);

			if (typeof(string) != memberType && TypeHelper.IsSameOrParent(typeof(ICloneable), memberType))
			{
				if (memberType.IsValueType)
					emit
						.box       (memberType)
						.callvirt  (typeof(ICloneable), "Clone")
						.unbox_any (memberType)
						;
				else
				{
					var valueIsNull = emit.DefineLabel();

					emit
						.dup
						.brfalse_s (valueIsNull)
						.callvirt  (typeof(ICloneable), "Clone")
						.castclass (memberType)
						.MarkLabel (valueIsNull)
						;
				}
			}

			if (mi is FieldInfo)
				emit.stfld   ((FieldInfo)mi);
			else
				emit.callvirt(setMethod);

			emit
				.ret()
				;
		}
		private void BuildTypedGetter(
			MemberInfo        mi,
			TypeBuilderHelper nestedType,
			string            typedPropertyName)
		{
			var methodType = mi.DeclaringType;
			var getMethod  = null as MethodInfo;

			if (mi is PropertyInfo)
			{
				getMethod = ((PropertyInfo)mi).GetGetMethod();

				if (getMethod == null)
				{
					if (_type != _originalType)
					{
						getMethod  = _type.GetMethod("get_" + mi.Name);
						methodType = _type;
					}

					if (getMethod == null || !IsMethodAccessible(getMethod))
						return;
				}
			}

			var methodInfo = _memberAccessor.GetMethod("Get" + typedPropertyName, typeof(object));

			if (methodInfo == null)
				return;

			var method = nestedType.DefineMethod(methodInfo);
			var emit   = method.Emitter;

			emit
				.ldarg_1
				.castType (methodType)
				.end();

			if (mi is FieldInfo) emit.ldfld   ((FieldInfo)mi);
			else                 emit.callvirt(getMethod);

			emit
				.ret()
				;
		}
		private void BuildIsNull(
			MemberInfo        mi,
			TypeBuilderHelper nestedType,
			Type              memberType)
		{
			var methodType = mi.DeclaringType;
			var getMethod  = null as MethodInfo;
			var isNullable = TypeHelper.IsNullable(memberType);
			var isValueType = (!isNullable && memberType.IsValueType);

			if (!isValueType && mi is PropertyInfo)
			{
				getMethod = ((PropertyInfo)mi).GetGetMethod();

				if (getMethod == null)
				{
					if (_type != _originalType)
					{
						getMethod  = _type.GetMethod("get_" + mi.Name);
						methodType = _type;
					}

					if (getMethod == null)
						return;
				}
			}

			var methodInfo = _memberAccessor.GetMethod("IsNull");

			if (methodInfo == null)
				return;

			var method = nestedType.DefineMethod(methodInfo);
			var emit   = method.Emitter;

			if (isValueType)
			{
				emit
					.ldc_i4_0
					.end()
					;
			}
			else
			{
				LocalBuilder locObj = null;

				if (isNullable)
					locObj = method.Emitter.DeclareLocal(memberType);

				emit
					.ldarg_1
					.castType (methodType)
					.end();

				if (mi is FieldInfo) emit.ldfld   ((FieldInfo)mi);
				else                 emit.callvirt(getMethod);

				if (isNullable)
				{
					emit
						.stloc(locObj)
						.ldloca(locObj)
						.call(memberType, "get_HasValue")
						.ldc_i4_0
						.ceq
						.end();
				}
				else
				{
					emit
						.ldnull
						.ceq
						.end();
				}
			}

			emit
				.ret()
				;
		}
		private void BuildSetter(MemberInfo mi, TypeBuilderHelper nestedType)
		{
			var methodType = mi.DeclaringType;
			var setMethod  = null as MethodInfo;

			if (mi is PropertyInfo)
			{
				setMethod = ((PropertyInfo)mi).GetSetMethod();

				if (setMethod == null)
				{
					if (_type != _originalType)
					{
						setMethod  = _type.GetMethod("set_" + mi.Name);
						methodType = _type;
					}

					if (setMethod == null || !IsMethodAccessible(setMethod))
						return;
				}
			}
			//else if (((FieldInfo)mi).IsLiteral)
			//	return;

			var method = nestedType.DefineMethod(_memberAccessor.GetMethod("SetValue", typeof(object), typeof(object)));
			var emit   = method.Emitter;

			emit
				.ldarg_1
				.castType (methodType)
				.ldarg_2
				.end();

			if (mi is FieldInfo)
			{
				var fi = (FieldInfo)mi;

				emit
					.CastFromObject (fi.FieldType)
					.stfld          (fi)
					;
			}
			else
			{
				var pi = (PropertyInfo)mi;

				emit
					.CastFromObject (pi.PropertyType)
					.callvirt       (setMethod)
					;
			}

			emit
				.ret()
				;

			nestedType.DefineMethod(_memberAccessor.GetProperty("HasSetter").GetGetMethod()).Emitter
				.ldc_i4_1
				.ret()
				;
		}
		private void BuildGetter(MemberInfo mi, TypeBuilderHelper nestedType)
		{
			var methodType = mi.DeclaringType;
			var getMethod  = null as MethodInfo;

			if (mi is PropertyInfo)
			{
				getMethod = ((PropertyInfo)mi).GetGetMethod();

				if (getMethod == null)
				{
					if (_type != _originalType)
					{
						getMethod  = _type.GetMethod("get_" + mi.Name);
						methodType = _type;
					}

					if (getMethod == null || !IsMethodAccessible(getMethod))
						return;
				}
			}

			var method = nestedType.DefineMethod(_memberAccessor.GetMethod("GetValue", typeof(object)));
			var emit   = method.Emitter;

			emit
				.ldarg_1
				.castType (methodType)
				.end();

			if (mi is FieldInfo)
			{
				var fi = (FieldInfo)mi;

				emit
					.ldfld          (fi)
					.boxIfValueType (fi.FieldType)
					;
			}
			else
			{
				if (methodType.IsValueType)
				{
					var loc = emit.DeclareLocal(methodType);

					emit
						.stloc      ((byte)loc.LocalIndex)
						.ldloca_s   ((byte)loc.LocalIndex);
				}

				var pi = (PropertyInfo)mi;

				emit
					.callvirt       (getMethod)
					.boxIfValueType (pi.PropertyType)
					;
			}

			emit
				.ret()
				;

			nestedType.DefineMethod(_memberAccessor.GetProperty("HasGetter").GetGetMethod()).Emitter
				.ldc_i4_1
				.ret()
				;
		}