反射概念:
1. 在程序运行时动态获取类或对象的信息,具体包括了
动态获取加载程序集(Assmebly)
动态获取类型信息(如类、接口 等) - Type对象
动态获取类型的成员信息(如方法,字段,属性等);
2. 在运行时,动态创建类型实例(new),以及调用和访问这些实例成员;
.Net反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为.Net的反射机制。
.Net反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;
类型 | 作用 |
Assembly | 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。 |
Module | 包含模块的程序集以及模块中的类等。还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 |
ConstructorInfo | 构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用Type的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。 |
MethodInfo |
方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信 息(如 abstract 或 virtual)等。使用Type的 GetMethods 或 GetMethod 方法来调用特定的方法。
|
FieldInfo | 字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。 |
EventInfo | 事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。 |
PropertyInfo | 属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。 |
ParameterInfo | 参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等 |
在程序运行时,动态获取程序集:
class Program
{
static void Main(string[] args)
{
Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
Person p = new Person();
p.TestAssembly();
Console.ReadKey();
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
private int Id;
public double Sum;
public void Method1() { }
private void Method2() { }
public void TestAssembly()
{
Assembly ass = this.GetType().Assembly;
Console.WriteLine(ass);
Type[] types = ass.GetTypes();
foreach (var item in types)
{
Console.WriteLine(item + " (types)");
}
Type currentType = ass.GetType();
Console.WriteLine(currentType);
Type typeByFullName = ass.GetType("ConsoleApp2.Person");
Console.WriteLine(typeByFullName);
Type type = this.GetType();
Console.WriteLine(type);
MethodInfo[] methods = this.GetType().GetMethods();
foreach (var item in methods)
{
Console.WriteLine(item + " (methods)");
}
var members = this.GetType().GetMembers();
foreach (var item in members)
{
Console.WriteLine(item);
}
var member = this.GetType().GetMember("Name");
foreach (var item in member)
{
Console.WriteLine(item);
}
FieldInfo field = type.GetField("Sum");
Console.WriteLine(field);
PropertyInfo prop = type.GetProperty("Name");
Console.WriteLine(prop);
}
}
在程序运行时,动态创建类型实例:
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.CreatePersonObject();
Console.ReadKey();
}
}
public void CreatePersonObject()
{
Type type = this.GetType();
Person p = Activator.CreateInstance(type) as Person;
Person p1 = Activator.CreateInstance<Person>();
PropertyInfo prop = type.GetProperty("Name");
prop.SetValue(p1, "toto",null);
Console.WriteLine(p1.Name);
MethodInfo method = type.GetMethod("SayHi");
method.Invoke(p1, null);
MethodInfo method1 = type.GetMethod("ShowNumber");
object[] arrParams = { 13 };
method1.Invoke(p1, arrParams);
MethodInfo method2 = type.GetMethod("GetString");
string retStr = method2.Invoke(p1, null).ToString();
Console.WriteLine(retStr);
}
public void SayHi()
{
Console.WriteLine("Hiiiiiiiiiiii");
}
public void ShowNumber(int no)
{
Console.WriteLine(no);
}
public string GetString()
{
return "Hello";
}
通过反射找出类型的构造函数,然后调用构造函数来获取实例引用
public static void GetConstructor()
{
Type tpdatetime = Type.GetType("System.DateTime", false);
if (tpdatetime != null)
{
ConstructorInfo constructor = tpdatetime.GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) });
if (constructor != null)
{
object instance = constructor.Invoke(new object[] { 2019, 12, 17, 16, 11, 24 });
if (instance != null)
{
PropertyInfo[] props = tpdatetime.GetProperties(BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine("以下是DateTime实例的属性值列表");
foreach (PropertyInfo item in props)
{
object objval = item.GetValue(instance,null);
Console.WriteLine("{0,-15}:{1}",item.Name,objval??string.Empty);
}
}
}
}
}
原文链接:https://www.cnblogs.com/czx1/p/201413137070-com.html
Activator.CreateInstance和Assembly.CreateInstance。这2种方法创建实例的区别:
https://www.cnblogs.com/loveleaf/p/9923970.html
Load、LoadFile、LoadForm:
Assembly assembly = Assembly.Load("Ruanmou.DB.Sqlserver");//1 动态加载 默认加载当前路径的dll文件,不需要后缀,该方法传入的是Dll的名字,该Dll必须位于全局缓存GAC中才行,不然会报“System.IO.FileLoadException: 未能加载文件或程序集”的异常。
Assembly assembly1 = Assembly.LoadFile(@"E:online720160928Advanced7Course2ReflectionMyReflectionMyReflectioninDebugRuanmou.DB.Sqlserver.dll");// 必须是完整路径
Assembly assembly2 = Assembly.LoadFrom("Ruanmou.DB.Sqlserver.dll");// 可以是当前路径 也可以是完整路径
动态判断对象属性值
判断一个对象里面 所有属性的值是否都为true:
public class Temp
{
public bool CalculationCompleted { get; set; }
public bool CollectionCompleted { get; set; }
public bool ConfigCompleted { get; set; }
public bool ExecCompleted { get; set; }
}
常见的写法可能是这样
Temp t = new Temp();
if (t.CalculationCompleted && t.CollectionCompleted && t.ConfigCompleted && t.ExecCompleted)
{
Console.WriteLine("所有属性值都为True");
}
这样子写没有毛病, 但是如果要判断的属性变多了呢,比如几十个,那么用这种方法写显而易见,代码量很大,而且只要Temp的属性增加了,就需要重新修改if判断,很不灵活。
下面换一种写法
public static bool IsAllCompleted<T>(T obj)
{
if (obj == null)
{
return false;
}
Type t = typeof(T);
//获取属性的集合
PropertyInfo[] pros = t.GetProperties();
foreach (var p in pros)
{
if (p.Name.Contains("Completed"))
{
//获取属性值
bool isCollectionCompleted = (bool)p.GetValue(obj, null);
if (!isCollectionCompleted)
{
//只要有一个数据为false就直接返回
return false;
}
}
}
return true;
}
Temp t = new Temp();
if (IsAllCompleted<Temp>(t))
{
Console.WriteLine("所有属性值都为True");
}
这种写法通过反射获取对象中所有属性,并获取值,然后循环判断值是否为false,显而易见,通过反射不需要管类中有多少个属性,不管是新增的属性还是删除的属性 ,只需要一个循环就可以得到所有属性的值,可以说非常灵活。
动态生成Sql
下面写一个我们经常写的Sql语句
Insert into Temp(CalculationCompleted,CollectionCompleted,ConfigCompleted,ExecCompleted) Values(@CalculationCompleted,@CollectionCompleted,@ConfigCompleted,@ExecCompleted)
这是一个参数化的插入Sql,如果表字段比较少,那这么写还好,但是如果很多,而且表字段不固定,那么这么写就不灵活了。
下面通过运用反射来动态生成Sql
首先需要这个表的实体类,我们还用Temp类
封装两个方法
/// <summary>
/// 返回属性名称(name, name, name)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static string GetParas<T>()
{
StringBuilder columns = new StringBuilder();
Type t = typeof(T);
PropertyInfo[] pros = t.GetProperties();
foreach (var item in pros)
{
if (item.PropertyType.Name == "IList`1" || item.PropertyType.Name.ToUpper().Contains("LIST"))
{
continue;
}
columns.Append(item.Name).Append(",");
}
return columns.Remove(columns.Length - 1, 1).ToString();
}
/// <summary>
/// 返回属性名称(@name,@name,@name)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static string GetATParas<T>()
{
StringBuilder columns = new StringBuilder();
Type t = typeof(T);
PropertyInfo[] properties = t.GetProperties();
foreach (var p in properties)
{
if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST"))
{
continue;
}
columns.Append("@").Append(p.Name).Append(",");
}
return columns.Remove(columns.Length - 1, 1).ToString();
}
string para = GetParas<Temp>();
string atPara = GetATParas<Temp>();
Console.WriteLine("Insert into Temp(" + para + ") Values(" + atPara + ")");
这样写,如果Temp表中新增的字段,那么只要实体类重新生成一下就可以了,sql语句完全不需要修改
动态调用类中的方法
先创建一个类
public class Temp
{
public bool CalculationCompleted { get; set; }
public bool CollectionCompleted { get; set; }
public bool ConfigCompleted { get; set; }
public bool ExecCompleted { get; set; }
public bool Calculation(DateTime time)
{
return true;
}
public bool Collection(DateTime time)
{
return true;
}
public bool Config(DateTime time)
{
return true;
}
public bool Exec(DateTime time)
{
return true;
}
}
常见的调用类方法
Temp t = new Temp();
DateTime time = new DateTime();
t.CalculationCompleted = t.Calculation(time);
t.CollectionCompleted = t.Collection(time);
t.ConfigCompleted = t.Config(time);
t.ExecCompleted = t.Exec(time);
这样子明显很不灵活。如果类成员属性、方法增加就需要在重新写N条t.XXXCompleted=t.XXX(time)
反射执行类方法
public static void ReflectExecMethod<T>(T obj)
{
string strReslutMsg = string.Empty;
Type t = typeof(T);
PropertyInfo[] properties = t.GetProperties();
foreach (var p in properties)
{
//获取属性值
bool isCollectionCompleted = (bool)p.GetValue(obj, null);
//判断属性值是否为false,如果是则执行方法
if (!isCollectionCompleted)
{
//方法需要的参数集合
object[] args = new object[] { DateTime.Now };
//获取方法名
string strMethodName = p.Name.Split(new string[] { "Completed" }, StringSplitOptions.RemoveEmptyEntries)[0];
//执行方法得到结果
bool result = (bool)t.GetMethod(strMethodName).Invoke(obj, args);
//赋值
p.SetValue(obj, result, null);
}
}
}
Temp t = new Temp();
ReflectExecMethod<Temp>(t);
通过反射调用类成员方法,并赋值 。。这样子写的好处,如果类成员方法、成员属性后面在增加了,主要符合规则,上面的代码就不需要修改。
原文链接:https://blog.csdn.net/cxhgg/article/details/80322929
通过反射调用类的私有成员:
Person p = new Person();
Type tPerson = p.GetType();
//得到私有字段的值:
FieldInfo privateField = tPerson.GetField("privateFields", BindingFlags.Instance | BindingFlags.NonPublic);
//设置私有成员的值:
privateField.SetValue(p, "修改后的私有字段值");
Console.WriteLine(privateField.GetValue(p));
//得到私有属性的值:
PropertyInfo privateProp = tPerson.GetProperty("PrivateProperties", BindingFlags.Instance | BindingFlags.NonPublic);
//设置私有属性的值:
privateProp.SetValue(p, "修改后的私有属性值",null);
Console.WriteLine(privateProp.GetValue(p,null));
//调用私有方法
MethodInfo privateMethod = tPerson.GetMethod("SayHi", BindingFlags.Instance | BindingFlags.NonPublic);
privateMethod.Invoke(p, null);