• c# 常用反射和表达式树整理


    更新: 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 

    所有要特别留意哦.

    很久没有写反射了,来整理一下呗.

    创建 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);
  • 相关阅读:
    Android — Camera聚焦流程
    Camera.Parameters 参数
    Android 中的 Service 全面总结
    android中Camera setDisplayOrientation使用
    Android动画学习笔记-Android Animation
    mediaplayer与surfaceView,无法播放问题
    android错误之MediaPlayer用法的Media Player called in state *,androidmediaplayer
    转:Android应用开发性能优化完全分析
    Android开发者指南(9) —— ProGuard
    计算机科学图书待读
  • 原文地址:https://www.cnblogs.com/keatkeat/p/12181646.html
Copyright © 2020-2023  润新知