我正在编写一个类来根据其他类型但修改后的属性动态生成类型,在我将属性部分添加到问题之前它工作正常,但在我添加以下代码来处理属性之后我尝试创建CustomAttributeBuilder时获取System.ArgumentException
class ModifiedTypeGenerator {
Dictionary<Type, Dictionary<PropertyInfo, List<Attribute>>> modelInfo;
public List<Type> GenerateModifiedTypes(Dictionary<Type,Dictionary<PropertyInfo,List<Attribute>>> models)
{
modelInfo = models;
List<Type> toReturn = new List<Type>();
foreach(Type model in modelInfo.Keys)
{
TypeBuilder tb = CreateTypeBuilder(model);
ConstructurBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
foreach(PropertyInfo propertyInfo in modelInfo[model].Keys)
{
CreateProperty(tb,model,propertyInfo);
}
Type newType = tb.CreateType();
toReturn.Add(newType);
}
return toReturn;
}
private TypeBuilder CreateTypeBuilder(Type model)
{
string typeName = "modified_" + model.Name;
AssemblyName assemblyName = new AssemblyName(typeName);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
model
);
return typeBuilder;
}
private void CreateProperty(TypeBuilder typeBuilder, Type model, PropertyInfo propertyInfo)
{
FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyInfo.Name, propertyInfo.PropertyType, FieldAttributes.Public);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyInfo.Name, PropertyAttributes.HasDefault, propertyInfo.PropertyType, null);
MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyInfo.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyInfo.PropertyType, Type.EmptyTypes);
MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propertyInfo.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { propertyInfo.PropertyType });
ILGenerator getIl = getMethodBuilder.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
ILGenerator setIl = setMethodBuilder.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethodBuilder);
propertyBuilder.SetSetMethod(setMethodBuilder);
AddAttributes(propertyBuilder,model,propertyInfo);
}
private void AddAttributes(PropertyBuilder propertyBuilder, Type model, PropertyInfo propertyInfo)
{
foreach(var attribute in modelInfo[model][propertyInfo])
{
CustomAttributeData customAttributeData =
propertyInfo.CustomAttributes.First(x => x.AttributeType == attribute.GetType());
var constructorArguments =
customAttributeData.ConstructorArguments.Select(x => x as object).ToArray();
CustomAttributeBuilder customAttributeBuilder =
new CustomAttributeBuilder(customAttributeData.Constructor, constructorArguments);
propertyBuilder.SetCustomAttribute(customAttributeBuilder);
}
}
}
将通过此方式运行的示例类型是:
public class TestModel
{
[RangeAttribute(1,100)]
public int Count { get; set;}
}
class Program
{
static void Main(string[] args)
{
List<Type> types = new List<Type>();
types.Add(typeof(TestModel));
GetModifiedTypes(types);
}
public static List<Type> GetModifiedTypes(List<Type> models)
{
Dictionary<Type, Dictionary<PropertyInfo, List<Attribute>>> modelInfo = new Dictionary<Type, Dictionary<PropertyInfo, List<Attribute>>>();
foreach(Type model in models)
{
modelInfo.Add(model, new Dictionary<PropertyInfo, List<Attribute>>());
foreach(PropertyInfo propertyInfo in model.GetProperties())
{
var customAttributeDataList = propertyInfo.GetCustomAttributes(typeof(Attribute), true).Select(x => x as Attribute).ToList();
for (int i = 0; i < customAttributeDataList.Count(); i++)
{
var atr= customAttributeDataList[i] as dynamic;
customAttributeDataList[i] = GetModifiedAttribute(atr);
}
modelInfo[model].Add(propertyInfo, customAttributeDataList);
}
}
ModifiedTypeGenerator mtg = new ModifiedTypeGenerator();
return mtg.GenerateModifiedTypes(modelInfo);
}
public static Attribute GetModifieAttribute(Attribute attribute)
{
return attribute;
}
public static RangeAttribute GetModifiedAttribute(RangeAttribute attribute)
{
Random r = new Random();
return new RangeAttribute(r.Next(), r.Next());
}
}
答案 0 :(得分:1)
问题是由这段代码引起的:
var constructorArguments = customAttributeData
.ConstructorArguments.Select(x => x as object).ToArray();
此处CustomAttributeData.ConstructorArguments
returns an IList<CustomAttributeTypedArgument>
,其元素(类型CustomAttributeTypedArgument
)被装箱为object
并尝试用作参数构造函数接受两个int32
参数。由于它们实际上不是int32
类型,因此抛出。
您最有可能要传递给属性构造函数的实际int32
值存储在CustomAttributeTypedArgument.Value
中。因此固定代码如下所示:
var constructorArguments = customAttributeData
.ConstructorArguments.Select(x => (object)x.Value).ToArray();