美文网首页csharpunity
Linq的妙用之筛选数据到字典

Linq的妙用之筛选数据到字典

作者: 雨落随风 | 来源:发表于2019-07-25 22:30 被阅读70次

在本文,笔者将教大家如何将数据筛选并保存到字典中,解决字典 key 不唯一导致的异常。

背景:

OnClick 同学奇思妙想,说要给方法加属性来标记他们,并通过标记好的索引的排列组合以及增减来决定方法执行顺序以及哪些方法需要被执行到,按他的说法呢,说是要用到建造者模式中。

代码:

先弄一个车的模板:

public class Car
{
    public string Name;
    public string Color;
    public int id;

    [MethodStep(step = 1)]
    public void SetName()
    {
    }

    [MethodStep(step = 2)]
    [MethodStep(step = 3)]
    [MethodStep(step = 4)]
    private static void SetColor()
    {
    }

    [MethodStep(step = 3)]
    public void SetID()
    {
    }
}

Tips:

  1. 仅仅是示意哈,所以方法内的实现省略。
  2. MethodStep 就是整个思路的重点,他决定了哪个方法需要执行,以及怎么个顺序执行。

紧接着我们使用扩展方法采集这些 Attribute 的信息,这也是本文的重点:Linq 的妙用

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
namespace IFramework
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
    public class MethodStepAttribute : Attribute
    {
        public int step;
        public MethodStepAttribute() { }
        public MethodStepAttribute(int step) { this.step = step; }
    }

    public static class IMethodRunnerExtension
    {
        public static T RunStepMethods<T>(this T t, int[] steps) where T : class
        {
            var methodsDic = typeof(T)
                .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
                .Where(v =>v.IsDefined(typeof(MethodStepAttribute)) &&v.GetParameters().Length == 0)
                .SelectMany(v => v.GetCustomAttributes(typeof(MethodStepAttribute)), (m, s) => new {(s as MethodStepAttribute).step, m })
                .GroupBy(v=>v.step,v=>v.m)
                .ToDictionary(v=>v.Key,v=>v.First());

            steps.ForEach((step) =>
            {
                if (methodsDic.ContainsKey(step))
                    methodsDic[step].Invoke(t, null);
                else
                    Log.E("No Such Func Step  " + step);
            });
            return t;
        }
    }
}

然后我们使用 Onclick 同学的思路构建一部车:

            Car car = new Car().RunStepMethods(new int[] { 1, 2, 3 });
//当然,你也可以偷工减料,少做一道工序:
            Car car = new Car().RunStepMethods(new int[] { 1, 3 });

对这个思路有兴趣的可以去他的码云仓库瞅瞅

讲解:

静下心来再配合需求与思路,上面的 Linq 扩展方法还是很好理解的。

  1. Where
    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

    • API解读:签名内的 this表明这是一个扩展方法,Where后面的一对尖括号“<>”表明他是泛型,需要传的只有一个参数,该参数是有一个返回值的委托。
    • 作用:就是断言并采集那些符合要求的所有的数据
    • 在本例中,就是初步筛选出符合条件的 MethodInfo(可以看到在本例,这个条件是方法必须加了特性且没有参数)。
  2. SelectMany
    public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

    • API 解读:选择集合性质的字段, 扩展方法 ,2 个委托类型的参数,前面参数为集合选择,它负责将你给的所有对象的指定字段采集起来,这个字段必须是数组这样的数据结构。(不然 selectmany 里面的Many还有啥意义呢?)。后面的参数是委托 Func 的返回值,通过使用匿名类型采集一些你关心数据。
    • 作用 : 就是选择集合性质的字段,并生成新的映射关系。
    • 在本例中,先将每个方法中的一个或者多个 MethodStepAttribute 采集并将 MethodStepAttribute 实例中的 step 字段与 MethodInfo 使用一个个匿名类型的实例搜集起来。
  3. GroupBy
    public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);

    • API解读:使用指定的键值作为依据对原数据进行分组 ,第二个参数则决定了要从原数据取出哪一个字段作为这个分组的值(值为集合)的元素。
    • 在本例中,通过 step 对 匿名类型的实例进行分组,然后取出 MethodInfo 作为最终输出。示例代码可以预见,Step = 3 时 MethodInfo 存在2个哦


      step是 分组信息的 key ,MethodInfo 是值
  4. ToDictionary
    public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);

    • API解读:通过指定的 key 将原数据或者原数据中指定的其他数据(字段)封装到字典。
    • 在本例中,笔者使用分组信息的 key 作为字典的 key(也就是 step ) ,将分组信息的值的第一位 MethodInfo 作为值 存储到字典。
    • 所以,该方法的第二个参数 就是避免字典添加元素时 key 重叠的关键一步,也是 GroupBy 的意义所在哈!
  5. 本例中为了简洁,使用了大量的 lambda 表达式。
    如所见:v=>v==1 是 等效于 (v)=>{return v==1;} 的。所以回过头去再看看,还会有不好理解的嘛?

结语:

通过这个示例我们 Get 到了 Linq 的更多魅力,是不是好满足哦!
还没有理解完全的,建议上手试试哦~

相关文章

  • Linq的妙用之筛选数据到字典

    在本文,笔者将教大家如何将数据筛选并保存到字典中,解决字典 key 不唯一导致的异常。 背景: OnClick 同...

  • Linq的用法总结

    一.linq的适用类型 二.linq的好处方便我们对保存的数据进行筛选,把数据保存为自己想要的排序,或者快速筛选出...

  • WPF 数据绑定(四)

    筛选的数据源的绑定,使用Linq Filter Data Collection。从数据集合中筛选符合设定条件的数据...

  • iOS使用NavigationViewController跳转以

    我的主界面有一个子界面做筛选,在筛选后想把筛选的条件字典返回主界面替换主界面的筛选字典的值,并且刷新主界面的数据 ...

  • python 字典相关操作

    1. python 在列表、字典、集合中筛选数据 列表:filter函数、列表解析 字典:字典解析 集合:集合解析...

  • C#3.0 LINQ(语言集成查询)

    定义 LINQ:将查询功能集成到C#语言的技术统称,它允许我们以SQL查询数据库的方式来查询数据集合 LINQ的查...

  • python进阶:第一章(数据结构与算法)

    问题一:如何在列表,字典,集合中根据条件筛选数据? 问题内容:如何找出列表中的负数?如何筛选出字典中值大于某个数值...

  • 课时18

    下一步 添加数据。 数据 在数据库里面查询 要筛选的话类似于字典的筛选。一个键值一个条件

  • Python之集合筛选

    如何在列表,字典,集合中根据条件筛选 核心:使用生成式 列表: 生成随机列表: 筛选方法: 字典: 生成字典: 筛...

  • Python奇技淫巧—[1]—在列表、字典、集合中根据条件筛选数

    Python奇淫巧技——在列表、字典、集合中根据条件筛选数据 通用做法:迭代 以列表为例: 筛选出下列数字大于等于...

网友评论

    本文标题:Linq的妙用之筛选数据到字典

    本文链接:https://www.haomeiwen.com/subject/zrkqrctx.html