0
|
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 }
|