.Net 反射 方法 用于调用泛型方法
核心代码:
- 通过Type下的GetMethod获取对应的方法信息
- 在通过MethodInfo下的MakeGenericMethod设置泛型参数
- 最后通过Invoke进行触发
注意:被反射的方法需要为public
访问权限
MethodInfo SetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set));
MethodInfo makeGenericMethod = SetMethod.MakeGenericMethod(entityType);
return (IQueryable)makeGenericMethod.Invoke(context, null);
例一:
反射DbContext
类中的DbContext.Set
方法
public static partial class CustomExtensions
{
/// <summary>
/// 通过指定实体类型名反射获取 IQueryable
/// </summary>
/// <param name="context"></param>
/// <param name="entityName"></param>
/// <returns></returns>
public static IQueryable GetDbSet(this DbContext context, string entityName)
{
IEntityType findEntityType = context.Model.FindEntityType(entityName);
return context.GetDbSet(findEntityType.ClrType);
}
/// <summary>
/// 通过指定实体类型反射获取 IQueryable
/// </summary>
/// <param name="context"></param>
/// <param name="entityType"></param>
/// <returns></returns>
public static IQueryable GetDbSet(this DbContext context, Type entityType)
{
MethodInfo SetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set));
MethodInfo makeGenericMethod = SetMethod.MakeGenericMethod(entityType);
return (IQueryable)makeGenericMethod.Invoke(context, null);
}
/// <summary>
///
/// </summary>
/// <typeparam name="Type"></typeparam>
/// <param name="context"></param>
/// <param name="entityType"></param>
/// <returns></returns>
public static IQueryable<T> GetDbSet<T>(this DbContext context, Type entityType)
{
MethodInfo SetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set));
MethodInfo makeGenericMethod = SetMethod.MakeGenericMethod(entityType);
return (IQueryable<T>)makeGenericMethod.Invoke(context, null);
}
}
例二:
反射DbHelper
类中的CheckDataBuild
方法
/// <summary>
/// 校验标识了CheckDataAttribute的字段,所对应的外键数据是否存在
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
/// <param name="errorMsgList"></param>
/// <param name="db"></param>
/// <returns></returns>
public static bool CheckData<T>(T item, List<string> errorMsgList, DatabaseContext db) where T : class
{
var t = typeof(T);
var props = t.GetProperties();
var success = true;
var methodInfo = typeof(DbHelper).GetMethod(nameof(CheckDataBuild));
foreach (var prop in props)
{
var attr = prop.GetCustomAttributes().OfType<CheckDataAttribute>().FirstOrDefault();
if (attr != null)
{
var val = prop.GetValue(item);
MethodInfo mi = methodInfo.MakeGenericMethod(attr.EntityType);
success = (bool)mi.Invoke(null, new object[] { errorMsgList, db, success, prop, attr, val });
}
}
return success;
}
/// <summary>
/// 数据校验
/// </summary>
/// <typeparam name="T2"></typeparam>
/// <param name="errorMsgList">错误信息</param>
/// <param name="db">db对象</param>
/// <param name="success">校验结果</param>
/// <param name="prop">属性信息</param>
/// <param name="attr">校验的特性</param>
/// <param name="val">值</param>
/// <returns></returns>
public static bool CheckDataBuild<T2>(List<string> errorMsgList, DatabaseContext db, bool success, PropertyInfo prop, CheckDataAttribute attr, object val) where T2 : class
{
var table = db.GetDbSet<T2>(attr.EntityType);
var existedItem = table.QueryByField(attr.FieldName, val, attr.EntityType);
if (existedItem == null)
{
success = false;
errorMsgList.Add($"Value {val} for filed {prop.Name} not available");
}
return success;
}
参考
C#里Type 如何转换成泛型T? - 知乎
C# Type传参转换成泛型T_雷小虎的专栏-CSDN博客