类型反射(Reflection),动态加载
using System.Reflection;
对象
类型完全限定名称
var fullName = typeof(Example).FullName;
创建对象
/// <summary>
/// 动态创建对象实例
/// </summary>
/// <typeparam name="T">要创建对象的类型</typeparam>
/// <param name="fullName">命名空间.类型名</param>
/// <param name="assemblyName">程序集</param>
/// <param name="args">参数组(数量、顺序、类型都匹配)</param>
/// <returns></returns>
public static object InvokeCreateInstance(string fullName, string assemblyName = null, object[] args = null)
{
try
{
if (assemblyName == null) // 本地程序集
{
Type o = Type.GetType(fullName, true, true);
object obj = Activator.CreateInstance(o, args);
return obj;
}
else
{
// 跨程序集
object ect = System.Reflection.Assembly.Load(assemblyName).CreateInstance(fullName, true, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.CreateInstance, Type.DefaultBinder, args, null, null);
return ect;
}
}
catch (Exception ex)
{
string err = ex.Message;
return null;
}
}
//Example obj = new Example();
var obj = WSComm.InvokeCreateInstance("WpfApp1.Example");
创建对象的方法对比
创建对象 | 耗时 | 备注 |
---|---|---|
new Example() | 1 | 直接创建对象,速度最快,标记为基准线 |
DynamicMethod | 3~5 | DynamicMehthodHelper |
Activator.CreateIntance(Type) | 7~10 | |
ContructorInfo.Invoke | 200~300 | |
Type.InvokeMember | 700~1000 | |
Assembly.CreateInstance(typeName) | 700~1000 | |
Activator.CreateInstance(assemblyName,typeName) | > 1000 | 最慢创建 |
触发事件
// 声明动态类型
private dynamic _dynamicObj;
......
// 定义对象事件
_dynamicObj = WSComm.InvokeCreateInstance("WpfApp1.Example");
_dynamicObj.MyEvent += new EventHandler(Dosth);
......
// 事件方法
private void Dosth(object sender, EventArgs e)
{
var arg = (MyEventArgs)e;
lbContent.Text = arg.Args.ToString();
}
// 响应事件
_dynamicObj.Eventrase = "Exec" + DateTime.Now.ToString();
获取控件
/// <summary>
/// 根据控件的字符串名称获取控件对象
/// </summary>
/// <typeparam name="T">要获取控件的类型</typeparam>
/// <param name="obj">控件所属对象</param>
/// <param name="ctlName">控件的名称</param>
/// <returns></returns>
public static T GetControlObject<T>(object obj, string ctlName)
{
try
{
Type mainType = obj.GetType();
var fi = mainType.GetField(ctlName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (fi != null)
{
T rlst = (T)fi.GetValue(obj);
return rlst;
}
else
{
return default(T);
}
}
catch (Exception)
{
return default(T);
}
}
var ctl = WSCommFunc.GetControlObject<TextBox>(this, "txtSpaceCnt1");
获取模板中元素控件
/// <summary>
/// 查找数据模板中的子元素控件
/// </summary>
/// <typeparam name="T">控件类型</typeparam>
/// <param name="parent">父控件</param>
/// <param name="predicate">谓语,判断条件</param>
/// <returns></returns>
public static T GetVisualChild<T>(DependencyObject parent, Func<T, bool> predicate) where T : Visual
{
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
DependencyObject v = VisualTreeHelper.GetChild(parent, i);
T child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v, predicate);
if (child != null)
{
return child;
}
}
else
{
if (predicate(child))
{
return child;
}
}
}
return null;
}
var ctl = GetVisualChild
(datagrid1, x => x.Name == "cbAll");
获取可视子元素
/// <summary>
/// 获取元素的可视子元素(根据父控件对象查找指定类型的子控件)
/// </summary>
/// <typeparam name="T">需要的类型</typeparam>
/// <param name="parent">所需元素的父级</param>
/// <returns></returns>
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
var scroll = GetVisualChild
(datagrid1);
设置控件
public static void CtlIsEnable(this System.Windows.Controls.Control ctl, bool bEnable = true)
{
ctl.IsEnabled = bEnable;
if (bEnable)
{
ctl.Background = new SolidColorBrush(Colors.Transparent);
}
else
{
ctl.Background = new SolidColorBrush(gray);
}
}
ctl.CtlIsEnable(false);
控件事件动态响应
RadioButton rbtn = WrapPanel1.Children[0] as RadioButton;
rbtn.IsChecked = true;
rbtn.RaiseEvent(new RoutedEventArgs(System.Windows.Controls.Primitives.ButtonBase.ClickEvent));
for (int i = 0; i < 3; i++)
{
RadioButton rdb = new RadioButton();
rdb.Width = 50;
rdb.VerticalAlignment = VerticalAlignment.Center;
rdb.Click += rbtn_Click;
rdb.Content = "Content" + i;
rdb.GroupName = groupName;
WrapPanel1.Children.Add(rdb);
}
对象的字典形式<属性描述,属性值>
// <summary>
/// 类型对象的字典形式<属性描述,属性值>
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="obj">对象</param>
/// <returns></returns>
public static Dictionary<string, object> ToDicDescValue<T>(this T obj) where T : class
{
var rslt = new Dictionary<string, object>();
foreach (var item in typeof(T).GetProperties())
{
rslt.Add(item.Name.GetDescription<T>(), InvokeGetProperty(obj, item.Name));
}
return rslt;
}
方法
方法的反射耗时相对较长,和直接调用方法相比,相差一个数量级。
一般方法
/// <summary>
/// 动态调用对象的方法
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="methodName">方法名称</param>
/// <param name="argsValue">参数值</param>
/// <param name="argsName">参数名称</param>
/// <returns></returns>
public static object InvokeMethod(object obj, string methodName, object[] argsValue, string[] argsName = null)
{
Type type = obj.GetType();
var binderAttr = BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
#if netle40
MethodInfo mi = type.GetMethod(methodName, binderAttr);
return mi?.Invoke(obj, binderAttr, Type.DefaultBinder, argsValue, null);
#else
return type.InvokeMember(methodName, binderAttr, Type.DefaultBinder, obj, argsValue, null, null, argsName);
#endif
}
// obj.FuncMethod("GGGG");
WSComm.InvokeMethod(obj, "FuncMethod", new object[] { "GGGG" });
/// <summary>
/// 动态方法调用对象的方法
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="methodName">方法名称</param>
/// <param name="argsValue">参数值</param>
/// <param name="argsName">参数名称</param>
/// <returns></returns>
public static object InvokeDynamicMethod(object obj, string methodName, object[] argsValue, string[] argsName = null)
{
MethodInfo methodInfo = obj.GetType().GetMethod(methodName);
var fastInvoker = DynamicMehthodHelper.GetMethodInvoker(methodInfo);
return fastInvoker(obj, argsValue);
}
// obj.FuncMethod("GGGG");
WSComm.InvokeDynamicMethod(obj, "FuncMethod", new object[] { "GGGG" });
其中,若有大量的方法反射需求,可以使用动态方法(DynamicMehthodHelper)调用对象的方法,或者使用方法的委托(GenerateDelegateHelper)提高反射调用的性能。
泛型方法
/// <summary>
/// 动态调用对象的泛型方法
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="methodName">方法名称</param>
/// <param name="parameters">参数值</param>
/// <param name="typeArguments">泛型的类型参数</param>
/// <returns></returns>
public static object InvokeGenericMethod(object obj, string methodName, object[] parameters, Type[] typeArguments)
{
Type type = obj.GetType();
MethodInfo mi = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
MethodInfo generic = mi?.MakeGenericMethod(typeArguments);
return generic?.Invoke(obj, parameters);
}
// obj.GenericMethod
(42);
WSComm.InvokeGenericMethod(obj, "GenericMethod", new object[] { 42 }, new Type[] { typeof(int) });
静态方法
/// <summary>
/// 动态调用对象的静态方法
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="methodName">方法名称</param>
/// <param name="parameters"></param>
/// <returns></returns>
static void InvokeStaticMethod(Type type, string methodName, params object[] parameters)
{
var binderAttr = BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
type.InvokeMember(methodName, binderAttr, Type.DefaultBinder, null, parameters);
}
// Example.StaticMethod("Static");
WSComm.InvokeStaticMethod(typeof(Example), "StaticMethod", "Static");
实体转换(相同属性赋值)
/// <summary>
/// 实体数据转换
/// </summary>
/// <typeparam name="Tdst">目标对象类型</typeparam>
/// <param name="source">源对象实体数据</param>
/// <param name="exceptSet">目标对象中不需要赋值的属性集合</param>
/// <returns>目标对象实体数据</returns>
/// <remarks>
/// 数据赋值时需要两个对象的属性名称保持一致
/// </remarks>
public static Tdst EntityMap<Tdst>(object source, params string[] exceptSet) where Tdst : class
{
if (source == null)
{
return default(Tdst);
}
var srcType = source.GetType();
Tdst rslt = Activator.CreateInstance<Tdst>();
var piDst = typeof(Tdst).GetProperties();
piDst.AsParallel().ForAll(item =>
{
if (exceptSet != null && exceptSet.Any(x => x == item.Name))
{
return;
}
var pi = srcType.GetProperty(item.Name);
if (pi != null && item.CanWrite)
{
try
{
item.SetValue(rslt, pi.GetValue(source, null), null);
}
catch (Exception ex)
{
var str = ex.Message;
}
}
});
return rslt;
}
/// <summary>
/// 实体数据转换
/// </summary>
/// <param name="source">源对象</param>
/// <param name="dest">需要赋值的目标对象</param>
/// <param name="exceptSet">目标对象中不需要赋值的属性集合</param>
/// <remarks>
/// 数据赋值时需要两个对象的属性名称保持一致
/// </remarks>
public static void EntityMap(object source, object dest, params string[] exceptSet)
{
if (source == null || dest == null)
{
return;
}
var srcType = source.GetType();
var piDst = dest.GetType().GetProperties();
piDst.AsParallel().ForAll(item =>
{
if (exceptSet != null && exceptSet.Any(x => x == item.Name))
{
return;
}
var pi = srcType.GetProperty(item.Name);
if (pi != null && item.CanWrite)
{
try
{
item.SetValue(dest, pi.GetValue(source, null), null);
}
catch (Exception ex)
{
var str = ex.Message;
}
}
});
}
实体集合转换(相同属性赋值)
/// <summary>
/// 实体数据转换
/// </summary>
/// <typeparam name="Tdst">目标实体</typeparam>
/// <param name="source">源实体数据</param>
/// <param name="exceptSet">目标数据不需要赋值的属性集合</param>
/// <returns>目标实体数据</returns>
/// <remarks>
/// 数据赋值时需要两个对象的属性名称保持一致
/// </remarks>
public static IList<Tdst> EntityMap<Tdst>(IEnumerable<object> source, params string[] exceptSet) where Tdst : class
{
List<Tdst> rslt = new List<Tdst>();
if (source == null)
{
return rslt;
}
foreach (object item in source)
{
rslt.Add(EntityMap<Tdst>(item, exceptSet));
}
return rslt;
}
// 当集合很大的时候,并发逻辑可以调整一下,转换速度可以调高10倍
private static readonly object _objEntityMap = new object();
public static IList<Tdst> EntityMapFast<Tdst>(IEnumerable<object> source, params string[] exceptSet) where Tdst : class, new()
{
List<Tdst> rslt = new List<Tdst>();
if (source == null || !source.Any())
{
return rslt;
}
var srcType = source.First().GetType();
var piDst = typeof(Tdst).GetProperties();
source.AsParallel().ForAll(src =>
{
var dest = new Tdst();
foreach (var item in piDst)
{
if (exceptSet != null && exceptSet.Any(x => x == item.Name))
{
continue;
}
var pi = srcType.GetProperty(item.Name);
if (pi != null && item.CanWrite)
{
try
{
item.SetValue(dest, pi.GetValue(src, null), null);
}
catch (Exception ex)
{
var str = ex.Message;
}
}
}
lock (_objEntityMap)
{
rslt.Add(dest);
}
});
return rslt;
}
属性
属性是否存在
/// <summary>
/// 对象是否包含属性
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="propertyName">属性名称(字符串形式)</param>
/// <returns>true包含属性、false不包含</returns>
public static bool InvokeContainProperty(object obj, string propertyName)
{
if (obj != null && !string.IsNullOrEmpty(propertyName))
{
var pi = obj.GetType().GetProperty(propertyName);
return pi != null;
}
return false;
}
/// <summary>
/// 对象是否包含属性
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="propertyName">属性名称(字符串形式)</param>
/// <returns>true包含属性、false不包含</returns>
public static bool InvokeContainProperty(object obj, params string[] propertyName)
{
if (obj == null)
{
return false;
}
var properties = obj.GetType().GetProperties().Select(s => s.Name).ToList();
foreach (var item in propertyName)
{
if (string.IsNullOrEmpty(item) || !properties.Contains(item))
{
return false;
}
}
return true;
}
// var val = obj.Value;
if (WSComm.InvokeContainProperty(obj, "Value"))
获取属性
/// <summary>
/// 动态获取对象的属性值
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="propertyName">属性名称(字符串形式)</param>
/// <param name="args">传递给属性用的参数</param>
/// <returns></returns>
public static object InvokeGetProperty(object obj, string propertyName, params object[] args)
{
Type type = obj.GetType();
#if netle40
var prop = type.GetProperty(propertyName);
if (null != prop && prop.CanRead)
{
return prop.GetValue(obj, null);
}
return null;
#else
// 如果不存在属性,会抛出异常
return type.InvokeMember(propertyName, BindingFlags.GetProperty, Type.DefaultBinder, obj, args);
#endif
}
// var val = obj.Value;
var val = WSComm.InvokeGetProperty(obj, "Value");
反射会影响性能,如果调用次数过多(比如100w次),会显著影响性能。
为提高效率,可以使用委托方法。把取值方法转换成委托,后续多次取值时直接调用委托。
设置属性
/// <summary>
/// 动态设置对象的属性
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="propertyName">属性名称(字符串形式)</param>
/// <param name="value">属性值</param>
public static void InvokeSetProperty(object obj, string propertyName, object value)
{
Type type = obj.GetType();
#if netle40
var pi = type.GetProperty(propertyName);
if (pi != null)
{
pi.SetValue(obj, GetObject(pi, value), null);
}
#else
type.InvokeMember(propertyName, BindingFlags.SetProperty, Type.DefaultBinder, obj, new object[] { value });
#endif
}
private static object GetObject(PropertyInfo pi, object value)
{
switch (pi.PropertyType.Name.ToLower())
{
case "int16":
return Convert.ToInt16(value);
case "int32":
return Convert.ToInt32(value);
case "int64":
return Convert.ToInt64(value);
case "string":
return Convert.ToString(value);
case "datetime":
return Convert.ToDateTime(value);
case "boolean":
return Convert.ToBoolean(value);
case "char":
return Convert.ToChar(value);
case "double":
return Convert.ToDouble(value);
case "decimal":
return Convert.ToDecimal(value);
default:
return value;
}
}
// obj.Value = 30;
WSComm.InvokeSetProperty(obj, "Value", 30);
设置批量初始化
/// <summary>
/// 对象属性初始化
/// </summary>
/// <param name="obj">指定的对象</param>
public static void InvokePropertyInit(object obj)
{
var piDst = obj.GetType().GetProperties();
piDst.AsParallel().ForAll(item =>
{
if (item.PropertyType == typeof(string))
{
InvokeSetProperty(obj, item.Name, string.Empty);
}
else if (item.PropertyType == typeof(int))
{
InvokeSetProperty(obj, item.Name, 0);
}
else if (item.PropertyType == typeof(bool))
{
InvokeSetProperty(obj, item.Name, false);
}
});
}
public void PrimitiveInit()
{
WSCommFunc.InvokePropertyInit(this);
}
获取属性注释值 Description
/// <summary>
/// 获取类中属性注释值
/// </summary>
/// <typeparam name="T">属性所属类型</typeparam>
/// <param name="propertyName">属性名称</param>
/// <returns>属性Description注释值</returns>
public static string GetDescription<T>(this string propertyName) where T: class
{
if (string.IsNullOrEmpty(propertyName))
{
return string.Empty;
}
var info = typeof(T).GetRuntimeProperty(propertyName);
if (info == null)
{
return propertyName;
}
var attribute = info.GetCustomAttribute<DescriptionAttribute>();
if (attribute != null)
{
return attribute.Description;
}
return string.Empty;
}
// "一个属性"
var description = nameof(obj.Value).GetDescription<Example>();
字段
获取字段
/// <summary>
/// 动态获取对象的字段值
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="fieldName">字段名称(字符串形式)</param>
/// <param name="args">传递给字段用的参数</param>
/// <returns></returns>
public static object InvokeGetField(object obj, string fieldName, params object[] args)
{
Type type = obj.GetType();
return type.InvokeMember(fieldName, BindingFlags.GetField, Type.DefaultBinder, obj, args);
}
// var val = obj.Name;
var val = WSComm.InvokeGetField(obj, "Name", null);
设置字段
/// <summary>
/// 动态设置对象的字段值
/// </summary>
/// <param name="obj">指定的对象</param>
/// <param name="fieldName">字段名称(字符串形式)</param>
/// <param name="value">字段值</param>
public static void InvokeSetField(object obj, string fieldName, object value)
{
Type type = obj.GetType();
type.InvokeMember(fieldName, BindingFlags.SetField, Type.DefaultBinder, obj, new object[] { value });
}
// obj.Name = "NewName";
WSComm.InvokeSetField(obj, "Name", "NewName");
Demo
public class Example
{
/// <summary>
/// 字段
/// </summary>
public string Name = "initialName";
/// <summary>
/// 属性
/// </summary>
[Description("一个属性")]
public int Value { get; set; } = 20;
/// <summary>
/// 事件
/// </summary>
public event EventHandler MyEvent;
private string _eventrase;
public string Eventrase
{
get => _eventrase;
set
{
if (_eventrase != value)
{
_eventrase = value;
MyEvent?.Invoke(this, new MyEventArgs { Args = _eventrase });
}
}
}
/// <summary>
/// 一般方法
/// </summary>
/// <param name="prefix"></param>
/// <returns></returns>
public string FuncMethod(string prefix)
{
return prefix + "REST";
}
/// <summary>
/// 泛型方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="display"></param>
/// <returns></returns>
public string GenericMethod<T>(T display)
{
return "Here it is: " + display.ToString();
}
/// <summary>
/// 全局静态方法
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public string StaticMethod(string arg)
{
return arg + "1234";
}
}
public class MyEventArgs : EventArgs
{
public object Args { get; set; }
}