c# 常用反射和表达式树整理
更新: 2021-06-19
反射 local function
local function 就是 Action or Func 来的.
var www = ""; void Abc(string dada) { www = dada; } var methodInfo = ((Action<string>)(Abc)).Method; methodInfo.Invoke(((Action<string>)(Abc)).Target, new object[] { "super man" }); // www = "super man"
可以通过强转换成 Action, 然后通过. Method 获取到 method info, 然后 invoke 的时候它没有 instance 但是有 .Target
想要检查某个 class 是否有实现某个接口, 最好的方式是拿它的 interfaces 出来找
public static bool HasImplementInterface(Type classType, Type interfaceType) { var requireIsGenericType = interfaceType.IsGenericType; var requireIsEmptyGeneric = interfaceType.ContainsGenericParameters; // is empty <,> ? return classType.GetInterfaces().Where(classInterface => { if (requireIsGenericType && requireIsEmptyGeneric) { if (!classInterface.IsGenericType) return false; return classInterface.GetGenericTypeDefinition() == interfaceType; } else { return classInterface == interfaceType; } }).Count() > 0; }
更新: 2020-02-22
每次想从 js 写好的代码翻译来 c# 就一定会遇到很多动态语言的问题
想写一个 groupby multiple column
linq 一般上用匿名对象 GroupBy(e => new { e.column1, e.column2 })
但是如果 column 是在 runtime 决定的呢?
直接写不出来, 因为匿名函数不可以简单的用反射写. 匿名函数实在 complie 的时候就创建好的了.
https://stackoverflow.com/questions/16838136/create-a-lambda-expression-with-a-new-anonymous-type-at-runtime
一个简单的解决方案是不要用 column 而是用拼接 string 的方式 group by
https://stackoverflow.com/questions/847066/group-by-multiple-columns
GroupBy(e => e.column1 + "分隔符" + e.column2 );
这个方案好不好,我不是很确定,但是简单是真的, 唯一要注意的是一定要加入分隔符.而且 value 最好都是 string
这种比较简单的场景下会比较安全. 如果不加分隔符 2 个 column 字是有可能撞的,
比如 abc + ef 和 ab + cef 最终都会等于 abcef
所有要特别留意哦.
很久没有写反射了,来整理一下呗.
旧的 : https://www.cnblogs.com/keatkeat/p/4819249.html
创建 Type
public class Abc {} var type = typeof(Abc); // class to type var type2 = new Abc().GetType(); // instance to type
有泛型的
public class Abc<T, U> {} var type = typeof(Abc<,>).MakeGenericType(new[] { typeof(string), typeof(string) });
创建实例
public class Abc{ public string name { get; set; } } var abc = Activator.CreateInstance(typeof(Abc)) as Abc;
有参数的
public class Abc { public Abc(string name) { } } var abc = Activator.CreateInstance(typeof(Abc), new object[] { "name" }) as Abc;
有可选参数的
public class Abc { public Abc(string name = "dada") { } } var abc = Activator.CreateInstance(typeof(Abc), BindingFlags.OptionalParamBinding, null, new object[] { Type.Missing }, CultureInfo.CurrentCulture) as Abc;
几个点留意一下
一定要有 BindingFlags.OptionalParamBinding, 也有人放完. BindingFlags.CreateInstance |
BindingFlags.Public |
BindingFlags.
Instance
BindingFlags.Instance和BindingFlags.Static二者必须有一项或者都有 (refer: https://blog.csdn.net/weixin_38109688/article/details/80147535)
Type.Missing 表示没有传 value
CultureInfo.CurrentCulture 不清楚用来干嘛.
获取方法
refer : https://stackoverflow.com/questions/3631547/select-right-generic-method-with-reflection 2个高赞的回答
一个是使用了 where 的方式去过滤方法.
方法重载主要是看generic, parameters (return 不看)
generic 只看数量 (where T : class 这个不管的)
parameters 就看数量和类型
步骤大概是把方法拿出来, 找 generic count -> make generic -> 检查所有参数数量类型和返回值. 这样就找到了.
第二种方法比较简单但是前提是你必须知道你要的类.
很巧妙的利用了 new Func 和 new Action 来选择方法, 泛型就用 object 后来补上.
public static MethodInfo GetMethod(Type classType, string methodName, Type[] paramTypes = null!, Type[] genericTypes = null!) { paramTypes ??= new Type[] { }; genericTypes ??= new Type[] { }; return classType.GetMethods() .Where(m => m.Name == methodName && m.GetGenericArguments().Count() == genericTypes.Count() && m.GetParameters().Count() == paramTypes.Count()) .Select(m => genericTypes.Count() > 0 ? m.MakeGenericMethod(genericTypes) : m) .Single(m => m.GetParameters().Select(p => p.ParameterType).SequenceEqual(paramTypes)); } public static ConstructorInfo GetConstructor(Type classType, Type[] paramTypes = null!) { paramTypes ??= new Type[] { }; return classType.GetConstructors() .Where(m => m.GetParameters().Count() == paramTypes.Count()) .Single(m => m.GetParameters().Select(p => p.ParameterType).SequenceEqual(paramTypes)); }
获取还没有泛型的 Type
var isOwnedBuilder = builderType.GetGenericTypeDefinition() == typeof(OwnedNavigationBuilder<,>);
lambda 获取属性
// e => var entityAsLambdaParameterExp = Expression.Parameter(entityClrType, "e"); // e.type var entityDotPropertyExp = Expression.Property(entityAsLambdaParameterExp, property); // e => e.type var getPropertyLambdaExp = Expression.Lambda( entityDotPropertyExp, entityAsLambdaParameterExp );
判断值类型
if (property.PropertyType.IsValueType || property.PropertyType == typeof(string))
判断有某个标签
var isHtmlContent = property.GetCustomAttribute<HTMLContentAttribute>() != null;
判断 Enum
if (property.PropertyType.IsEnum)
判断泛型 List
var isSSources = property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(List<>) && property.PropertyType.GetGenericArguments()[0] == typeof(SSource);