1.场景:在对接接口遇到Post(multipart/form-data)提交数据时对接的参数名称出现如“model.no”格式的参数。。
2.思路:看到这种第一时间想到的是最简单快捷的 在写name名的时候直接写“model.no”。但往往实际业务中参数需要进行加密,一般我们把加密方法写好传入字典类(Dictionary)循环取值加密,今天我这里写了一个参数Model。
3.操作
3.1 用字典类操作方法(可以在加密的时候进行为空判断):
3.2 使用的实体类,但实体类的属性命名是不能带小数点的。方法一“model.no”换成“model_no“,循环取值时用String..Replace("-",".")。方法二使用特性在属性上标记表单提交时参数的名称。这里使用的是方法二。
创建特性FormDataName
/// <summary> /// 表单提交时用的参数名 /// </summary> public class FormDataNameAttribute : Attribute { public FormDataNameAttribute(String parameterNmae) { this.ParameterNmae = parameterNmae; } public String ParameterNmae { get; private set; } }
创建反射方法,根据传入的实体生成对应的表单提交格式数据(这里创建了一个model接收返回的数据,也可以用字典类)。
/// <summary> /// 只支持嵌套一层list的实体 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public List<PostDataClass> convertData<T>(T model) { List<PostDataClass> postList = new List<PostDataClass>(); foreach (System.Reflection.PropertyInfo p in model.GetType().GetProperties()) { if (p.GetValue(model) == null) continue; if (!p.PropertyType.IsGenericType) { //获取字段特性 object[] objAttrs = p.GetCustomAttributes(typeof(FormDataNameAttribute), true); //有特性则取特性值作为参数名 string prop = objAttrs.Length > 0 ? ((FormDataNameAttribute)objAttrs[0]).ParameterNmae : p.Name.ToString(); //字段值 string value = p.GetValue(model).ToString(); postList.Add(new PostDataClass(prop, value, 0)); } else { // 如List<T>,返回类名T string className = p.PropertyType.GetGenericArguments()[0].Name; // 获取该泛型属性值,返回一个列表,如List<Man>; // 因为是反射返回的数据,无法直接转换为List使用,针对这种数据,反射机制对这种属性值提供了 // “Count”列表长度、“Item”子元素等属性; object obj = p.GetValue(model, null); // 获取列表List<T>长度 int count = Convert.ToInt32(obj.GetType().GetProperty("Count").GetValue(obj, null)); for (int i = 0; i < count; i++) { // 获取列表子元素,然后子元素其实也是一个类,然后递归调用当前方法获取类的所有公共属性 object item = obj.GetType().GetProperty("Item").GetValue(obj, new object[] { i }); //重复操作 foreach (System.Reflection.PropertyInfo p1 in item.GetType().GetProperties()) { if (p1.GetValue(item) == null) continue; if (!p1.PropertyType.IsGenericType) { object[] objAttrs = p1.GetCustomAttributes(typeof(FormDataNameAttribute), true); string prop = objAttrs.Length > 0 ? ((FormDataNameAttribute)objAttrs[0]).ParameterNmae : p1.Name.ToString(); string value = p1.GetValue(item).ToString(); postList.Add(new PostDataClass(prop, value, 0)); } } } } } return postList; }
PostDataClass是我这需要返回的实体类,实际可根据不同需要反射成不同的数据格式。主要思路是先反射实体,判断数据不为空就且类型非泛型类型就直接取属性名与值。如果是泛型的话使用GetProperty("Count")获取数据的数量与GetProperty("Item")获取数据值,拿到数据之后再循环去里面找数据不为泛型的直接取值,是泛型的再去循环。目前需求只嵌套了一层所以就没判断泛型里面还有泛型的情况。