Mercurial > pub > bltoolkit
diff Source/TypeBuilder/Builders/GeneratedAttributeBuilder.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/GeneratedAttributeBuilder.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using BLToolkit.Reflection; + +namespace BLToolkit.TypeBuilder.Builders +{ + internal class GeneratedAttributeBuilder : AbstractTypeBuilderBase + { + private CustomAttributeBuilder _attributeBuilder; + + public GeneratedAttributeBuilder(Type attributeType, object[] arguments, string[] names, object[] values) + { + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + + ConstructorInfo constructor = null; + + if (arguments == null || arguments.Length == 0) + { + constructor = attributeType.GetConstructor(Type.EmptyTypes); + arguments = Type.EmptyTypes; + } + else + { + // Some arguments may be null. We can not infer a type from the null reference. + // So we must iterate all of them and got a suitable one. + // + foreach (ConstructorInfo ci in attributeType.GetConstructors()) + { + if (CheckParameters(ci.GetParameters(), arguments)) + { + constructor = ci; + break; + } + } + } + + if (constructor == null) + throw new TypeBuilderException(string.Format("No suitable constructors found for the type '{0}'.", attributeType.FullName)); + + if (names == null || names.Length == 0) + { + _attributeBuilder = new CustomAttributeBuilder(constructor, arguments); + } + else if (values == null || names.Length != values.Length) + { + throw new TypeBuilderException(string.Format("Named argument names count should match named argument values count.")); + } + else + { + List<PropertyInfo> namedProperties = new List<PropertyInfo>(); + List<object> propertyValues = new List<object>(); + List<FieldInfo> namedFields = new List<FieldInfo>(); + List<object> fieldValues = new List<object>(); + + for (int i = 0; i < names.Length; i++) + { + string name = names[i]; + MemberInfo[] mi = attributeType.GetMember(name); + + if (mi.Length == 0) + throw new TypeBuilderException(string.Format("The type '{0}' does not have a public member '{1}'.", attributeType.FullName, name)); + + if (mi[0].MemberType == MemberTypes.Property) + { + namedProperties.Add((PropertyInfo)mi[0]); + propertyValues.Add(values[i]); + } + else if (mi[0].MemberType == MemberTypes.Field) + { + namedFields.Add((FieldInfo)mi[0]); + fieldValues.Add(values[i]); + } + else + throw new TypeBuilderException(string.Format("The member '{1}' of the type '{0}' is not a filed nor a property.", name, attributeType.FullName)); + } + + _attributeBuilder = new CustomAttributeBuilder(constructor, arguments, + namedProperties.ToArray(), propertyValues.ToArray(), namedFields.ToArray(), fieldValues.ToArray()); + } + } + + private static bool CheckParameters(ParameterInfo[] argumentTypes, object[] arguments) + { + if (argumentTypes.Length != arguments.Length) + return false; + + for (int i = 0; i < arguments.Length; i++) + { + if (arguments[i] == null && argumentTypes[i].ParameterType.IsClass) + continue; + + if (argumentTypes[i].ParameterType.IsAssignableFrom(arguments[i].GetType())) + continue; + + // Bad match + // + return false; + } + + return true; + } + + public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) + { + return context.IsAfterStep && context.BuildElement == BuildElement.Type == TargetElement is TypeHelper; + } + + public override void Build(BuildContext context) + { + if (context.BuildElement == BuildElement.Type) + { + context.TypeBuilder.TypeBuilder.SetCustomAttribute(_attributeBuilder); + } + else if (TargetElement is MethodInfo) + { + context.MethodBuilder.MethodBuilder.SetCustomAttribute(_attributeBuilder); + } + else if (TargetElement is PropertyInfo && context.IsAbstractProperty) + { + if (_attributeBuilder != null) + { + var field = context.Fields[(PropertyInfo)TargetElement]; + + field.SetCustomAttribute(_attributeBuilder); + + // Suppress multiple instances when the property has both getter and setter. + // + _attributeBuilder = null; + } + } + } + } +}