C#反射(Reflection)与特性(Attribute)实例

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; }
    }
FormDataNameAttribute

  创建反射方法,根据传入的实体生成对应的表单提交格式数据(这里创建了一个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;
        }
ReflectData
PostDataClass是我这需要返回的实体类,实际可根据不同需要反射成不同的数据格式。主要思路是先反射实体,判断数据不为空就且类型非泛型类型就直接取属性名与值。如果是泛型的话使用GetProperty("Count")获取数据的数量与GetProperty("Item")获取数据值,拿到数据之后再循环去里面找数据不为泛型的直接取值,是泛型的再去循环。目前需求只嵌套了一层所以就没判断泛型里面还有泛型的情况。
原文地址:https://www.cnblogs.com/binzi/p/12909660.html