.net基础--反射

1、什么是反射

元数据是指程序以及类型信息的数据,它包含在程序集中(程序集包含:元数据,编译代码,资源)。

在.net中反射是查看和操作元数据的动作。

2、为什么要用反射

  • 在程序运行时,动态加载需要的程序集,以便操作其元数据。(例如有些IOC容器的实现,就是通过配置对应程序集,在运行时动态加载这些程序集,实现注入)
  • 构造出可重用性的代码,通过反射可以动态的绑定/获取数据(例如orm中将查询结果转成实体,在更新数据时需要获取实体信息构造更新语句)。

3、.net中使用反射常用的类型

1)Assembly

当我们需要加载程序集时,可以通过Assembly.LoadFrom,或者Assembly.LoadFile方法加载指定程序集。有了程序集我们就可以获取程序集中类型了。

2)Type

Type(类型),我们可以通过Assembly.GetType获取指定的类型,也可以通过Assembly.GetTypes获取程序集中所有的类型。

当然我们也可以通过GetType方法获取变量的类型,还可以使用typeof获取指定类型。

 

Type中常用方法(以下方法都有对应根据名称获取相应类型的方法,也是很常用,此处略过):

上面列举的方法都有相应重载方法,通过BindingFlags(使用位运算)指定获取对应的类型

例如获取实例非公有方法:

var privateMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);

BindingFlags(以下仅列举常用的,详情可以参考BindingFlags枚举信息)

        //仅类型内部声明的(不包含父类型的)
        DeclaredOnly = 2, 
        //实例成员
        Instance = 4,  
        //静态成员
        Static = 8, 
        //公有
        Public = 16,  
        //非公有
        NonPublic = 32,
...

 

简单代码示例

 1             var assembly = Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "QinGY.DotnetCoreStudy.SimpleNetCore.dll"));
 2             var types = assembly.GetTypes();
 3             var type = types.FirstOrDefault(p => p.Name == "SaleOrder");
 4             //  var type = assembly.GetType("SaleOrder");
 5             if (type == null)
 6             {
 7                 throw new Exception("SaleOrder不存在");
 8             }
 9             else
10             {
11                 #region 示例--列举Type中的类型
12                 var constructors = type.GetConstructors();
13 
14                 Console.WriteLine($"总共有{constructors.Length}个构造方法");
15 
16                 var events = type.GetEvents();
17                 if (events != null)
18                 {
19                     foreach (var eventItem in events)
20                     {
21                         Console.WriteLine($"事件:{eventItem.Name}");
22                     }
23                 }
24 
25                 var properties = type.GetProperties();
26                 foreach (var propertyItem in properties)
27                 {
28                     Console.WriteLine($"属性类型:{propertyItem.PropertyType}  属性名称:{propertyItem.Name}");
29                 }
30                 var fields = type.GetFields();
31                 foreach (var fieldItem in fields)
32                 {
33                     Console.WriteLine($"字段类型:{fieldItem.FieldType} 字段名称:{fieldItem.Name}");
34                 }
35 
36                 var members = type.GetMembers();
37                 foreach (var memberItem in members)
38                 {
39                     Console.WriteLine($"成员类型:{memberItem.MemberType} 成员名称:{memberItem.Name}");
40                 }
41 
42                 var methods = type.GetMethods();
43                 foreach (var methodItem in methods)
44                 {
45                     Console.WriteLine($"方法名称:{methodItem.Name}");
46                 }
47 
48                 var privateMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
49                 foreach (var privateMethodItem in privateMethods)
50                 {
51                     Console.WriteLine($"非公有方法名称:{privateMethodItem.Name}");
52                 }
53                 #endregion
54                 // 创建对象
55                 var instance = Activator.CreateInstance(type);
56                 //指定参数构造函数创建对象
57                 object[] parameters = new object[] {
58                 "amz0001",DateTime.Now,1 };
59                 var instance2 = Activator.CreateInstance(type, parameters);
60                 //调用方法
61                 var method = type.GetMethod("GetOrderInfo", BindingFlags.Instance | BindingFlags.Public);
62                 method.Invoke(instance2, null);
63                 //获取/设置属性
64                 var pro = type.GetProperty("OrderNumber");
65                 var val = pro.GetValue(instance2);
66                 Console.WriteLine("ordernumber:" + val.ToString());
67                 pro.SetValue(instance2, "W00001");
68                 val = pro.GetValue(instance2);
69                 Console.WriteLine("修改后ordernumber:" + val.ToString());
70 
71             }
View Code

 

反射泛型方法,需要调用MakeGenericMethod指定参数实际类型。

--泛型-------------------
    public class Manager
    {
        public void Process<T>(T t) where T : BaseRequestDto
        {
            Console.WriteLine("请求访问....获取数据");
        }
    }





---调用----------------


            var newManager = Activator.CreateInstance(typeof(Manager));
            var method = typeof(Manager).GetMethod("Process");
            //method.Invoke(newManager, null);  ///直接调会出现异常!!!
            var gMethod = method.MakeGenericMethod(typeof(ProductRequestDto));
            gMethod.Invoke(newManager, null);
View Code

 

 

 

 

在实际项目中用到的关于反射例子

一、.netcore中依赖注入业务服务

 1             #region  服务注入
 2             Assembly assembly = Assembly.Load("qingy.Service");
 3             List<Type> types = assembly.GetTypes().Where(p => p.IsClass && !p.IsAbstract && !p.IsGenericType
 4             && p.GetInterfaces().Any(x => x == typeof(IService))
 5             ).ToList();
 6             foreach (var item in types)
 7             {
 8                 services.AddTransient(item);
 9 
10             }
11             #endregion

 

二、通过反射获取枚举的描述信息

 1         public static Dictionary<string, string> GetEnumDescription(Type enumType)
 2         {
 3             var result = new Dictionary<string, string>();
 4             var fields = enumType.GetFields();
 5             foreach (var item in fields)
 6             {
 7                 if (item.FieldType.IsEnum)
 8                 {
 9                     object[] descriptionAttributes = item.GetCustomAttributes(typeof(DescriptionAttribute), false);
10                     result.Add(item.Name, descriptionAttributes.Length < 1 ? item.Name : ((DescriptionAttribute)descriptionAttributes[0]).Description);
11                 }
12             }
13             return result;
14         }

 

 三、使用反射构造实体映射(略)

 

4、反射性能非常差?不要用反射?

待定

特性(Attribute)

特性(Attribute),是指.net公共语言运行时允许添加类似关键字的声明信息。它可以声明在类、属性、方法等元数之上。

特性一般都是为元素添加附加的关键信息,通常是通过反射得到这些附件信息进行对应的处理。

常见的特性:Serializable,JsonProperty,MaxLength,DllImport等等。

自定义特性
    [AttributeUsage(AttributeTargets.All,AllowMultiple =false,Inherited =false)]
    public class CommentAttribute:Attribute
    {
        /// <summary>
        /// 备注
        /// </summary>
        public string CommentString { get; set; }
        /// <summary>
        /// 长度
        /// </summary>
        public int Length { get; set; }
    }

说明:

1、特性必须继承自Attribute;

2、在特性类之上添加AttributeUsage可以定义特性的使用范围(通过AttributeTargets限定声明的元素;通过AllowMultiple限定是否可以多次声明,通过Inherited限定继承关系)

3、使用[]包住声明到对应的元素之上即可。

注:自定义特性一般都是通过反射获取信息并处理(代码略)

posted on 2020-12-29 00:11  john_yong  阅读(582)  评论(0编辑  收藏  举报

导航