comparison Source/TypeBuilder/Builders/GeneratedAttributeBuilder.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using System.Reflection.Emit;
5 using BLToolkit.Reflection;
6
7 namespace BLToolkit.TypeBuilder.Builders
8 {
9 internal class GeneratedAttributeBuilder : AbstractTypeBuilderBase
10 {
11 private CustomAttributeBuilder _attributeBuilder;
12
13 public GeneratedAttributeBuilder(Type attributeType, object[] arguments, string[] names, object[] values)
14 {
15 if (attributeType == null)
16 throw new ArgumentNullException("attributeType");
17
18 ConstructorInfo constructor = null;
19
20 if (arguments == null || arguments.Length == 0)
21 {
22 constructor = attributeType.GetConstructor(Type.EmptyTypes);
23 arguments = Type.EmptyTypes;
24 }
25 else
26 {
27 // Some arguments may be null. We can not infer a type from the null reference.
28 // So we must iterate all of them and got a suitable one.
29 //
30 foreach (ConstructorInfo ci in attributeType.GetConstructors())
31 {
32 if (CheckParameters(ci.GetParameters(), arguments))
33 {
34 constructor = ci;
35 break;
36 }
37 }
38 }
39
40 if (constructor == null)
41 throw new TypeBuilderException(string.Format("No suitable constructors found for the type '{0}'.", attributeType.FullName));
42
43 if (names == null || names.Length == 0)
44 {
45 _attributeBuilder = new CustomAttributeBuilder(constructor, arguments);
46 }
47 else if (values == null || names.Length != values.Length)
48 {
49 throw new TypeBuilderException(string.Format("Named argument names count should match named argument values count."));
50 }
51 else
52 {
53 List<PropertyInfo> namedProperties = new List<PropertyInfo>();
54 List<object> propertyValues = new List<object>();
55 List<FieldInfo> namedFields = new List<FieldInfo>();
56 List<object> fieldValues = new List<object>();
57
58 for (int i = 0; i < names.Length; i++)
59 {
60 string name = names[i];
61 MemberInfo[] mi = attributeType.GetMember(name);
62
63 if (mi.Length == 0)
64 throw new TypeBuilderException(string.Format("The type '{0}' does not have a public member '{1}'.", attributeType.FullName, name));
65
66 if (mi[0].MemberType == MemberTypes.Property)
67 {
68 namedProperties.Add((PropertyInfo)mi[0]);
69 propertyValues.Add(values[i]);
70 }
71 else if (mi[0].MemberType == MemberTypes.Field)
72 {
73 namedFields.Add((FieldInfo)mi[0]);
74 fieldValues.Add(values[i]);
75 }
76 else
77 throw new TypeBuilderException(string.Format("The member '{1}' of the type '{0}' is not a filed nor a property.", name, attributeType.FullName));
78 }
79
80 _attributeBuilder = new CustomAttributeBuilder(constructor, arguments,
81 namedProperties.ToArray(), propertyValues.ToArray(), namedFields.ToArray(), fieldValues.ToArray());
82 }
83 }
84
85 private static bool CheckParameters(ParameterInfo[] argumentTypes, object[] arguments)
86 {
87 if (argumentTypes.Length != arguments.Length)
88 return false;
89
90 for (int i = 0; i < arguments.Length; i++)
91 {
92 if (arguments[i] == null && argumentTypes[i].ParameterType.IsClass)
93 continue;
94
95 if (argumentTypes[i].ParameterType.IsAssignableFrom(arguments[i].GetType()))
96 continue;
97
98 // Bad match
99 //
100 return false;
101 }
102
103 return true;
104 }
105
106 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders)
107 {
108 return context.IsAfterStep && context.BuildElement == BuildElement.Type == TargetElement is TypeHelper;
109 }
110
111 public override void Build(BuildContext context)
112 {
113 if (context.BuildElement == BuildElement.Type)
114 {
115 context.TypeBuilder.TypeBuilder.SetCustomAttribute(_attributeBuilder);
116 }
117 else if (TargetElement is MethodInfo)
118 {
119 context.MethodBuilder.MethodBuilder.SetCustomAttribute(_attributeBuilder);
120 }
121 else if (TargetElement is PropertyInfo && context.IsAbstractProperty)
122 {
123 if (_attributeBuilder != null)
124 {
125 var field = context.Fields[(PropertyInfo)TargetElement];
126
127 field.SetCustomAttribute(_attributeBuilder);
128
129 // Suppress multiple instances when the property has both getter and setter.
130 //
131 _attributeBuilder = null;
132 }
133 }
134 }
135 }
136 }