类型反射(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; }
}
posted @ 2019-12-31 18:12  wesson2019  阅读(333)  评论(0编辑  收藏  举报