• 浅析LINQ涉及的一些C#语言特性


    时间:午饭后

    地点:苏州公司

    主题:Entity Framework涉及的一些C#语言特性,要讲的语言特性,如下图所示

    1.Extension Methods

    很旧的主题了,DebugLZQ以前也有相关的博文提过。用个简单点的例子来说吧

    下面的例子完成一个计算某个月剩余天数的功能,我们可以如下编码:调用一个静态帮助类的静态方法。

    using System;
    
    namespace ExtensionMethods
    {
        class Program
        {
            static void Main(string[] args)
            {
                DateTime dateTime = new DateTime(2013, 3, 22);
                int daysTillEndOfMonth = DateUtilities.DaysToEndOfMonth(dateTime);
                Console.WriteLine(daysTillEndOfMonth);
                Console.ReadKey();
            }
    
        }
    
        public static class DateUtilities
        {
            public static int DaysToEndOfMonth(DateTime dateTime)
            {
                return DateTime.DaysInMonth(dateTime.Year, dateTime.Month) - dateTime.Day;
            }
        }
    }

    这样写当然没什么问题。很多时候就是这样用的
    如果我们用扩展方法,可以如下实现,注意区别在哪里!

    using System;
    
    namespace ExtensionMethods
    {
        class Program
        {
            static void Main(string[] args)
            {
                DateTime dateTime = new DateTime(2013, 3, 22);
                int daysTillEndOfMonth = dateTime.DaysToEndOfMonth();
                Console.WriteLine(daysTillEndOfMonth);
                Console.ReadKey();
            }
    
        }
    
        public static class DateUtilities
        {
            public static int DaysToEndOfMonth(this DateTime dateTime)
            {
                return DateTime.DaysInMonth(dateTime.Year, dateTime.Month) - dateTime.Day;
            }
        }
    }

    下面用扩展方法实现的程序明显比上面的普通函数调用,更容易阅读。

    其实,扩展方法也就是C#的一个语法糖衣,其编译过后也是方法的调用,其优点是更容易阅读,因为其可以为一些固有的类如DateTime、String...扩展一些方法。

     2.Query Language

     下面通过上面的扩展方法,来实现数据查询。可以实现如下:

    using System;
    using System.Collections.Generic;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] {"Suzhou","Wuxi","Changzhou","Zhenjiang","Nanjing","Shanghai"};
                IEnumerable<string> query = cities.StringThatStartWith("S");
                
                foreach(var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
        }
        //写一个扩展方法用迭代器实现过滤
        public static class FilterExtension
        {
            public static IEnumerable<string> StringThatStartWith(this IEnumerable<string> input,string start)
            {
                foreach(var s in input)
                {
                    if (s.StartsWith(start))
                        yield return s;
                }
            }
        }
    }

    上面的代码运行当然也木有什么问题,但是实现方法有点繁琐。
    可以初步简化如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] {"Suzhou","Wuxi","Changzhou","Zhenjiang","Nanjing","Shanghai"};
                IEnumerable<string> query = cities.StringThatStartWith("S");
                
                foreach(var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
        }
        //
        public static class FilterExtension
        {
            public static IEnumerable<string> StringThatStartWith(this IEnumerable<string> input,string start)
            {
                return input.Where(s => s.StartsWith(start));
            }
        }
    }

    进一步简化:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] {"Suzhou","Wuxi","Changzhou","Zhenjiang","Nanjing","Shanghai"};
                IEnumerable<string> query = cities.Where(s => s.StartsWith("S"));
    
                foreach(var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
        }
    }

    不喜欢这种写法?可以用LINQ来写,如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] {"Suzhou","Wuxi","Changzhou","Zhenjiang","Nanjing","Shanghai"};
                //IEnumerable<string> query = cities.Where(s => s.StartsWith("S"));
                IEnumerable<string> query = from city in cities
                                            where city.StartsWith("S")
                                            select city;
                foreach(var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
        }
    }

    3.Oh,Holy Shit!

    Where从哪里冒出来的!盗用了MS的东西!这里:

    IEnumerable<string> query = cities.Where(s => s.StartsWith("S"));//这个“Where”,MS是怎么做到的?自己定义一个Filter怎么样?

    让我们回到那个扩展方法,从头来实现 ,如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] { "Suzhou", "Wuxi", "Changzhou", "Zhenjiang", "Nanjing", "Shanghai" };
                IEnumerable<string> query = cities.Filter(StringThatStartWith);
    
                foreach (var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
    
            static bool StringThatStartWith(string item,string startWord)
            {
                return item.StartsWith(startWord);
            }
        }
        //委托作为扩展方法的参数
        public static class FilterExtension
        {
            public delegate bool FilterDelegate(string item,string startWord);
    
            public static IEnumerable<string> Filter(this IEnumerable<string> input, FilterDelegate fDelegate)
            {
                foreach (var item in input)
                {
                    if (fDelegate(item,"S"))
                        yield return item;
                }
            }
        }
    }

     程序运行OK。既然传入一个委托调用函数可以,那么直接传入匿名不更简单,如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] { "Suzhou", "Wuxi", "Changzhou", "Zhenjiang", "Nanjing", "Shanghai" };
                //匿名方法简化
                IEnumerable<string> query = cities.Filter(delegate(string item,string startWord)
                                                              {
                                                                  return item.StartsWith(startWord);
                                                              });
    
                foreach (var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
    
            //static bool StringThatStartWith(string item,string startWord)
            //{
            //    return item.StartsWith(startWord);
            //}
        }
        //委托作为扩展方法的参数
        public static class FilterExtension
        {
            public delegate bool FilterDelegate(string item,string startWord);
    
            public static IEnumerable<string> Filter(this IEnumerable<string> input, FilterDelegate fDelegate)
            {
                foreach (var item in input)
                {
                    if (fDelegate(item,"S"))
                        yield return item;
                }
            }
        }
    }

    直接用Lambda来简化吧,如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] { "Suzhou", "Wuxi", "Changzhou", "Zhenjiang", "Nanjing", "Shanghai" };
                //Lambda  
                //至此实现了同“Where”长相一样的方法!
                IEnumerable<string> query = cities.Filter((item, startWord) => item.StartsWith(startWord));
    
                foreach (var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
    
            //static bool StringThatStartWith(string item,string startWord)
            //{
            //    return item.StartsWith(startWord);
            //}
        }
        //委托作为扩展方法的参数
        public static class FilterExtension
        {
            public delegate bool FilterDelegate(string item,string startWord);
    
            public static IEnumerable<string> Filter(this IEnumerable<string> input, FilterDelegate fDelegate)
            {
                foreach (var item in input)
                {
                    if (fDelegate(item,"S"))
                        yield return item;
                }
            }
        }
    }

    --------
    大功告成,利用MS的Where背后的这些C#语法特性,实现了一个类似的Where。 

    等等..........

    貌似忘了一个东西,对Func<>/Action<>委托啊,干嘛自己定义?

    重新写下,如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ExtensionQuery
    {
        class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> cities = new[] { "Suzhou", "Wuxi", "Changzhou", "Zhenjiang", "Nanjing", "Shanghai" };
                //Lambda  
                //至此实现了同“Where”长相一样的方法!
                IEnumerable<string> query = cities.Filter((item, startWord) => item.StartsWith(startWord));
    
                foreach (var city in query)
                {
                    Console.WriteLine(city);
                }
                Console.ReadKey();
            }
    
            //static bool StringThatStartWith(string item,string startWord)
            //{
            //    return item.StartsWith(startWord);
            //}
        }
        //委托作为扩展方法的参数
        public static class FilterExtension
        {
            //public delegate bool FilterDelegate(string item,string startWord);
            //用Func<>委托取代自定义的委托
            public static IEnumerable<string> Filter(this IEnumerable<string> input, Func<string,string,bool> fDelegate)
            {
                return input.Where(item => fDelegate(item,"S"));
            }
        }
    }

     这下OK了

    4.Lambda Expressions 

    Lambda表达式可以有多个参数、一个参数,或者没有参数。其参数类型可以隐式或者显式。示例代码如下:

    1. (x, y) => x * y //多参数,隐式类型=> 表达式
    2. x => x * 5 //单参数, 隐式类型=>表达式
    3. x => { return x * 5; } //单参数,隐式类型=>语句块
    4. (int x) => x * 5 //单参数,显式类型=>表达式
    5. (int x) => { return x * 5; } //单参数,显式类型=>语句块
    6. () => Console.WriteLine() //无参数

    上述格式都是Lambda表达式的合法格式,在编写Lambda表达式时,可以忽略参数的类型,因为编译器能够根据上下文直接推断参数的类型。

    5.Func<T>和Expression<T>

     这个源自园子里的一个博问,问题如下:

    Func<TObject, bool>是委托(delegate)

    Expression<Func<TObject, bool>>是表达式

    Expression编译后就会变成delegate,才能运行。比如

    Expression<Func<int, bool>> ex = x=>x < 100;

    Func<int, bool> func = ex.Compile();

    然后你就可以调用func:

    func(5) //-返回 true

    func(200) //- 返回 false

    而表达式是不能直接调用的。

    参考:http://stackoverflow.com/questions/793571/why-would-you-use-expressionfunct-rather-than-funct

    关于EF中用哪个你可以看看这篇文章:Entity Framework - Func引起的数据库全表查询

    关于如何将多个expression合并为一个可以写多个where:

    .where(expression1).where(expression2)...

    运行时EF会自动合并优化的

     小结

    1.下面两种写法都行

    IEnumerable<string> cities = new[] { "Suzhou", "Wuxi", "Changzhou", "Zhenjiang", "Nanjing", "Shanghai" };
    //IEnumerable<string> cities = new string[] { "Suzhou", "Wuxi", "Changzhou", "Zhenjiang", "Nanjing", "Shanghai" };//OK also

    构建一个可枚举的集合,这是新特性,逆变与协变(和“父类可以替换子类”相似)。

    2.类似“Where”的语法如何自己构建。
    3.Lambda表达式的写法。譬如说{}。

  • 相关阅读:
    ElasticSearch入门 第一篇:Windows下安装ElasticSearch
    怎样打开.jar格式文件,怎样运行.jar格式文件
    如何安装java环境和如何配置java环境
    JDK安装、java环境配置
    学习PHP好,还是Python好呢?
    艾伟:WPF简介 狼人:
    艾伟:ASP.NET MVC,深入浅出IModelBinder,在Post方式下慎用HtmlHelper 狼人:
    艾伟:在Mono平台开发前你应该知道 狼人:
    艾伟:一个较完整的关键字过滤解决方案(上) 狼人:
    艾伟:闲话WPF之一(WPF的结构) 狼人:
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/2975379.html
Copyright © 2020-2023  润新知