C#提升(二、反射)

一、什么是反射

C#编写的程序会编译成一个程序集(.DLL或.exe),其中会包含元数据、编译代码和资源,通过反射可以获取到程序集中的信息
通俗来讲,反射就是我们在只知道一个对象的外部而不了解内部结构的情况下,可以知道这个对象的内部实现

反射:System.Reflection .Net框架提供的帮助类库,可以读取并使用metadata

1.1 普通的写法

很明显我们创建了一个Mysql的调用实例,并且使用了Query的方法

IDBHelper dBHelper = new MysqlHelper();
dBHelper.Query();

1.2 使用反射

Assembly assembly = Assembly.Load("lyrics.db.Mysql"); // dll 名称 从当前目录加载
Type type = assembly.GetType("lyrics.db.Mysql.MysqlHelper");
object ohelper = Activator.CreateInstance(type);
IDBHelper dBHelper1 = (IDBHelper)ohelper;
dBHelper1.Query();

1.3 Assembly的不同加载

Assembly assembly = Assembly.Load("lyrics.db.Mysql"); // dll 名称 从当前目录加载
Assembly assembly1 = Assembly.LoadFile(@"D:\Demo\Demo\bin\Debug\lyrics.db.Mysql.dll"); // 完整路径加载,可以是别的目录
Assembly assembly2 = Assembly.LoadFrom("lyrics.db.Mysql.dll");

二、工厂模式+反射

2.1 Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
	<appSettings>
		<add key="IDBHelperConfig" value="lyrics.db.Mysql,lyrics.db.Mysql.MysqlHelper"/>
	</appSettings>
</configuration>

2.2 Factory

public class Factory
{
    private static string IDBHelperConfig = ConfigurationManager.AppSettings["IDBHelperConfig"];
    private static string DllName = IDBHelperConfig.Split(',')[0];
    private static string TypeName = IDBHelperConfig.Split(',')[1];
    public static IDBHelper CreateHelper() {
        Assembly assembly = Assembly.Load(DllName); // dll 名称 从当前目录加载
        Type type = assembly.GetType(TypeName);
        object ohelper = Activator.CreateInstance(type);
        return (IDBHelper)ohelper;
    }
}

这样我们就可以修改配置文件和对应目录下的dll来使用不同的数据库

三、反射创建不同类型实例

3.1 普通无参

Assembly assembly = Assembly.Load("lyrics.db.Mysql"); // dll 名称 从当前目录加载
Type type = assembly.GetType("lyrics.db.Mysql.MysqlHelper");
object ohelper = Activator.CreateInstance(type);

3.2 私有构造函数

object ohelper2 = Activator.CreateInstance(type,true); // 第二个参数可以调用私有构造函数,可以破坏单例

3.3 含参构造函数

object ohelper3= Activator.CreateInstance(type, new object[] { 123});// 调用含参的构造函数

3.4 泛型类

Type type2 = assembly.GetType("lyrics.db.Mysql.MysqlHelper`3"); // 泛型获取类型使用`3代表此泛型类有三个泛型参数
var newType = type2.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) });//指定三个泛型参数分别为int、string、DateTime
object ohelper4 = Activator.CreateInstance(newType);

四、反射调用方法

4.1 无参方法

var method = type.GetMethod("Query");
method.Invoke(ohelper, null);

4.2 有参方法

var method2 = type.GetMethod("Query");
method.Invoke(ohelper, new object[] { 123 });

4.3 静态类型

var method3 = type.GetMethod("Query");
method.Invoke(ohelper, new object[] { "asfhgiaksf" });
method.Invoke(null, new object[] { "asfhgiaksf" }); // 静态类型可以不传实例

4.4 重载方法

var method4 = type.GetMethod("Query",new Type[] { }); //无参的重载方法
method.Invoke(ohelper, new object[] { });

4.5 私有方法

var method5 = type.GetMethod("Query", BindingFlags.Instance| BindingFlags.NonPublic); 
method.Invoke(ohelper, new object[] { });

4.6 泛型类+泛型方法

Type type1 = assembly.GetType("lyrics.db.Mysql.MysqlHelper`1"); // 代表lyrics.db.Mysql.MysqlHelper这个类只有一个泛型参数
Type type2 = type1.MakeGenericType(new Type[] { typeof(int)});// 设置lyrics.db.Mysql.MysqlHelper这个泛型类的具体类型为 int
object obj = Activator.CreateInstance(type2); // 创造对应的实例
MethodInfo methodInfo = type2.GetMethod("Query"); // 获取其中的函数
MethodInfo methodInfo1 = methodInfo.MakeGenericMethod(new Type[] { typeof(string),typeof(DateTime)});//设置参数类型为string、dateTime
methodInfo1.Invoke(obj, new object[] {123,"safas",DateTime.Now });// 掉用方法

五、反射字段/属性

People people = new People() { Id = 123, Name = "ly", Description = "saffasf" };

Type type = typeof(People);
object oPeople= Activator.CreateInstance(type);
foreach (var prop in type.GetProperties()) {
	Console.WriteLine(prop.Name);
	Console.WriteLine(prop.GetValue(oPeople));
	if (prop.Name.Equals("Id")) {
	 prop.SetValue(oPeople, 234);
	}
	Console.WriteLine($"{type.Name}.{prop.Name}={prop.GetValue(oPeople)}");
}

字段与属性类似

六、反射的优劣

6.1 优势

动态

6.2 局限

  1. 代码复杂
  2. 绕过编译检查
  3. 性能缺陷

你可能感兴趣的:(c#,mysql,开发语言)