中匿名函数,实例化和采纳委托以及委托在

先前平昔迷迷糊糊的,今后毕竟搞掌握。

一、匿名类:[ C# 叁.0/.NET 三.x 新增特色 ]

一、简介

  委托是一类别型,由重要字delegate申明。确切的说,委托是一种可用来封装命名只怕匿超情势的引用类型。 
它好像于 C++
中的函数指针,而且是项目安全和保证的。

  委托项指标宣示与格局签名相似,有二个重回值和专擅数目任意档次的参数。必须利用全体分外重临类型和输入参数的诀窍或
lambda 表达式实例化委托。

  委托允许将艺术作为参数进行传递。
  委托可用以定义回调方法。
  委托能够链接在一块儿;例如,能够对二个风浪调用多少个艺术。
  方法不必与信托签名完全相称。

本文内容

  • 信托和泛型委托
    • 委托发展:C# 中央委员托的迈入
    • 泛型委托
  • 委托
    • 声明(定义)委托
    • 实例化委托
    • 调用委托
    • 用 拉姆da表明式创设和实例化委托
  • .NET 提供的信托
    • Action 委托
    • Func 委托
    • Predicate 委托
  • 参考资料
  • 修改记录

Lambda表达式

一.1 倒霉意思,作者匿了

   在付出中,大家有时会像上边包车型客车代码壹样声Bellamy(Bellamy)个匿名类:能够看出,在匿名类的语法中并从未为其命名,而是直接的1个new
{
}
就做到了。从外表看来,大家根本十分小概知道那些类是干神马的,也不精晓它有什么意义。

澳门葡京备用网址 1)

                    var annoyCla1 = new


    {

        ID = 10010,

        Name = "EdisonChou",

        Age = 25


    };

 

    Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);

澳门葡京备用网址 2)

  经过调节和测试运维,大家发现匿名类完全能够兑现具名类的机能:

澳门葡京备用网址 3

二、Delegate

   Delegate至少0个参数,至多三十二个参数,能够无重临值,也能够钦点重返值类型。

     public delegate int MethodDelegate(int x, int y);
        private static MethodDelegate method;
        static void Main(string[] args)
        {
            method = new MethodDelegate(Add);
            Console.WriteLine(method(10,20));
            Console.ReadKey();
        }

        private static int Add(int x, int y)
        {
            return x + y;
        }

 

下载 Deom

Lamda表明式基本写法是()=>{ };
拉姆da和措施一致都能够流传参数和拥有重返值。(int x)=>{return x;};
拉姆da表达式并不是C#独有的,此外语言也保有Lambda表明式。

一.二 深切匿名类背后

   既然大家发现匿名类能够完全实现具名类的意义,那么我们得以大胆推断编写翻译器肯定在内部帮大家转移了二个近似具名类的class,于是,大家仍旧依靠反编写翻译工具对其进展追究。通过Reflector反编写翻译,大家找到了编写翻译器生成的匿名类如下图所示:

澳门葡京备用网址 4

  从上图能够看到:

  (1)匿名类被编写翻译后会生成三个[泛型类]中匿名函数,实例化和采纳委托以及委托在。,能够见到上海体育地方中的<>f__AnonymousType0<<ID>j__TPar,
<Name>j__TPar, <Age>j__TPar>正是一个泛型类;

  (二)匿名类所生成的天性都以只读的,能够看出与其相应的字段也是只读的;

  澳门葡京备用网址 5

  所以,要是我们在先后中为属性赋值,那么会油然则生错误;

  澳门葡京备用网址 6

  (3)能够见到,匿名类还重写了基类的多个主意:Equals,GetHashCode和ToString;我们能够看看它为大家所生成的ToString方法是怎么来促成的:

  澳门葡京备用网址 7

  完成的作用如下图所示:

澳门葡京备用网址 8

三、Func<T>

 在利用 Func<T, TResult> 委托时,不必显式定义一个装进唯有一个参数的措施的委托。

 以下示例简化了此代码,它所用的法子是实例化 Func<T, TResult> 委托,而不是显式定义二个新委托并将命有名的模特式分配给该信托。

public class GenericFunc
{
   public static void Main()
   {
      // 依旧是用命名方法实例化委托类型
      Func<string, string> convertMethod = UppercaseString;
      string name = "Dakota";
      // 依旧是通过委托实例调用该方法
      Console.WriteLine(convertMethod(name));
   }

   private static string UppercaseString(string inputString)
   {
      return inputString.ToUpper();
   }
}

上面包车型客车演示演示怎么着评释和采用 Func<T, TResult> 委托。  

此示例声澳优个 Func<T, TResult> 变量,并为其分配了2个将字符串中的字符转换为题写的
lambda 表明式。  

接着将封装此方法的委托传递给Enumerable.Select 方法,以将字符串数组中的字符串更改为大写。

static class Func
{
   static void Main(string[] args)
   {
      // 声明了一个Func委托类型的变量selector并用Lambda表达式进行实例化 
      // 这个Lambda表达式将用来获取一个字符串并将这个字符串转化为大写并返回
      Func<string, string> selector = str => str.ToUpper();

      // 创建一个字符串数组
      string[] words = { "orange", "apple", "Article", "elephant" };
      // 依次遍历这个字符串数组并调用委托实例selector进行处理
      IEnumerable<String> aWords = words.Select(selector);

      // 输出结果到控制台
      foreach (String word in aWords)
         Console.WriteLine(word);
   }
}      
/*
This code example produces the following output:

   ORANGE
   APPLE
   ARTICLE
   ELEPHANT
*/

 

下载更加多 德姆o

某个文书档案上写Lambda是匿名函数,小编觉着是颠三倒4的,拉姆da能够象征二个匿名函数,不过还足以来代表Linq说明式啊。

壹.三 匿名类的共享

  能够设想一下,倘诺我们的代码中定义了累累匿名类,那么是否编写翻译器会为每种匿名类都生成三个泛型类呢?答案是不是定的,编译器驰念得很远,幸免了双重地生成类型。换句话说,定义了多个匿名类的话假设符合自然原则则能够共享贰个泛型类。上面,大家就来探望有哪几种情状:

  (壹)如若定义的匿名类与事先定义过的1模1样:品质类型和顺序都平等,那么暗中认可共享前八个泛型类

澳门葡京备用网址 9)

                    var annoyCla1 = new


            {

                ID = 10010,

                Name = "EdisonChou",

                Age = 25


            };

 

            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,

                annoyCla1.Name, annoyCla1.Age);

            Console.WriteLine(annoyCla1.ToString());

 

                        // 02.属性类型和顺序与annoyCla1一致,那么共同使用一个匿名类


                    var annoyCla2 = new


                {

                    ID = 10086,

                    Name = "WncudChou",

                    Age = 25


                };

            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,

                annoyCla1.Name, annoyCla1.Age);

            Console.WriteLine("Is The Same Class of 1 and 2:{0}",

                annoyCla1.GetType() == annoyCla2.GetType());    

澳门葡京备用网址 10)

  通过上述代码中的最终两行:大家能够判定其是还是不是是1个连串?答案是:True

澳门葡京备用网址 11

  (贰)要是属性名称和种种一致,但性能类型不相同,那么如故同步利用1个泛型类,只是泛型参数改变了罢了,所以在运行时会生成不同的类:

澳门葡京备用网址 12)

                    var annoyCla3 = new


                {

                    ID = "EdisonChou",

                    Name = 10010,

                    Age = 25


                };

            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla3.ID,

                annoyCla3.Name, annoyCla3.Age);

            Console.WriteLine("Is The Same Class of 2 and 3:{0}",

                annoyCla3.GetType() == annoyCla2.GetType());

澳门葡京备用网址 13)

  大家正好聊起尽管共享了同3个泛型类,只是泛型参数改变了罢了,所以在运行时会生成不同的类。所以,那么可以揣摸到最终两行代码所出示的结果应该是False,他们就算都选择了叁个泛型类,可是在运行时生成了五个例外的类。

澳门葡京备用网址 14

  (三)假若数据型名称和档次相同,但逐一分化,那么编写翻译器会另行创建2个匿名类

澳门葡京备用网址 15)

                    var annoyCla4 = new


                {

                    Name = "EdisonChou",

                    ID = 10010,

                    Age = 25


                };

            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla4.ID,

                annoyCla4.Name, annoyCla4.Age);

            Console.WriteLine("Is The Same Class of 2 and 4:{0}",

                annoyCla4.GetType() == annoyCla2.GetType());

澳门葡京备用网址 16)

  运转判断结果为:False

澳门葡京备用网址 17

  通过Reflector,能够窥见,编写翻译器确实重新生成了2个泛型类:

澳门葡京备用网址 18

四、Action<T>

Action 委托:未有传来参数,也从没回去类型,即Void。如:

void Main(string[] args)
        {
            Action say = SayHello;
            say();
        }
        public static void SayHello( )
        {
           Console.WriteLine("Say Hello");
        }

Action<T> 信托:传入参数为T,未有回去类型。如:

void Main(string[] args)
        {
            Action<string> say = SayHello;
            say("Hello");
        }
        public static void SayHello(string word )
        {
            Console.WriteLine(word);
        }

其实ActionFunc的用法差不离,差距只是叁个有重回类型,二个尚无回来类型,当然Action也足以接匿名方法和Lambda表达式。

匿有名的模特式:

void Main(string[] args)
        {
            Action<string> say = delegate(string word)
            {
                Console.WriteLine(word);
            };
            say("Hello Word");
        }

Lambda表达式:

 static void Main(string[] args)
        {
            Action<string> say = s => Console.WriteLine(s);
            say("Hello Word");
        }

 

寄托和泛型委托


委托完成了函数指针,那几个函数指针跟 C
的函数指针分化,它是项目安全的,确认保证被调用的不二等秘书籍签名是没有错的。只要方法签名跟委托签名相配,给委托的实例能够是实例方法,或是静态方法。

何以要有这些事物?我们对把多少作为函数参数很纯熟,但有时,有些方法的操作不是指向数据,而是本着另四个办法。比如,线程,用线程去履行八个主意,或是代码段;再例如,事件,事件是委托的特例,等等。

delegate委托

贰、匿名方式:[ C# 二.0/.NET 二.0 新增特色 ]

五、Predicate<T>

 泛型委托:表示定义壹组条件并分明内定对象是还是不是顺应那么些标准的办法。此委托由
Array 和 List 类的三种格局运用,用于在集合中搜索成分。

void Main(string[] args)
        {
            Point[] points = { new Point(100, 200), 
            new Point(150, 250), new Point(250, 375), 
            new Point(275, 395), new Point(295, 450) };
            Point first = Array.Find(points, ProductGT10);
            Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
            Console.ReadKey();
        }
        private static bool ProductGT10(Point p)
        {
            if (p.X * p.Y > 100000)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

选择含有 Array.Find 方法的 Predicate 委托搜索 Point 结构的数组。

1旦 X 和 Y 字段的乘积大于 100,000,此委托代表的主意 ProductGT10 将赶回
true。

Find 方法为数组的各种成分调用此委托,在适合测试条件的首先个点处截至。

寄托发展:C# 中央委员托的迈入

  • C# 1.0
    中,通过用在另内地点定义的章程显式开始化委托来创立委托的实例。
  • C# 2.0 引进了匿名方式(anonymous
    method)的定义,用匿名情势早先化委托,在信托中施行未命名的内联语句块。
  • C# 三.0 引入了 Lambda
    表明式,与匿有名的模特式的定义类似,但更具表现力并且更简便。匿名情势和
    Lambda 表明式统称为“匿名函数”,类似闭包(Closure)性子。
  • 平凡,针对 .NET Framework 3.5 及越来越高版本应运用 拉姆da 表明式。

上面包车型大巴示范演示了从 C# 1.0 到 C# 三.0 委托创立进度的前进:

示例1:

澳门葡京备用网址 19澳门葡京备用网址 20View Code

namespace MyDelegate
{
    class Program
    {
        delegate void TestDelegate(string s);

        static void M(string s)
        {
            System.Console.WriteLine(s);
        }

        static void Main(string[] args)
        {
            // C# 1.0: 最初的委托语法,用一个方法名初始化委托.
            TestDelegate testdelA = new TestDelegate(M);

            // C# 2.0: 用内联代码初始化委托,这个内联代码成为“匿名方法”.
            // 这个方法把一个字符串作为输入参数.
            TestDelegate testDelB = delegate(string s) { System.Console.WriteLine(s); };

            // C# 3.0: 用 Lambda 表达式初始化委托. 
            // Lambda 表达式也把一个字符串(x)作为输入参数.
            // 编译器可以推断 x 的数据类型.
            TestDelegate testDelC = (x) => { System.Console.WriteLine(x); };

            // 调用委托.
            testdelA("Hello. My name is M and I write lines.");
            testDelB("That's nothing. I'm anonymous and ");
            testDelC("I'm a famous author.");

            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
    }
}

运维结果:

澳门葡京备用网址 21澳门葡京备用网址 22View Code

Hello. My name is M and I write lines.
That's nothing. I'm anonymous and
I'm a famous author.
Press any key to exit.

委托基本的利用包含声称2个委托、实例化一个委托、使用四个信托

贰.一 从委托的宣示提起

  C#中的匿有名的模特式是在C#2.0引进的,它甘休了C#贰.0事先版本申明委托的绝无仅有方法是行职分名格局的一代。但是,那里大家照旧看一下在未有匿名方式从前,大家是如何阐明委托的。

  (一)首先定义一个寄托项目:

public
                            delegate
                                    void DelegateTest(string testName);

  (二)编写一个相符委托规定的命有名的模特式:

                    public
                            void TestFunc(string name)

        {

            Console.WriteLine("Hello,{0}", name);

        }

  (三)最后声美赞臣(Meadjohnson)(Nutrilon)个寄托实例:

    DelegateTest dgTest = new DelegateTest(TestFunc);

    dgTest("Edison Chou");

  (四)调节和测试运营能够收获以下输出:

澳门葡京备用网址 23

  由地点的步凑能够看看,我们要声雅培(Abbott)个寄托实例要为其编制3个符合规定的命名格局。可是,尽管程序中这些格局只被这一个委托行使的话,总会感觉到代码结构有点浪费。于是,微软引入了匿名格局,使用匿名情势注脚委托,就会使代码结构变得简洁,也会省去实例化的一部分支出。

六、总结

    Delegate至少0个参数,至多三十五个参数,能够无重临值,也足以钦赐再次来到值类型

  Func尚可0个至15个传入参数,必须怀有重回值

  Action还可以0个至拾伍个传入参数,无再次来到值

  Predicate只可以接受2个传播参数,重回值为bool类型

 

参照小说:

泛型委托

示例 壹 也可改写成泛型格局。如下所示:

示例 2:

澳门葡京备用网址 24澳门葡京备用网址 25View Code

namespace MyGenericDelegate
{
    class Program
    {
        delegate void TestGenericDelegate<T>(T s);

        static void GenericM<T>(T s)
        {
            System.Console.WriteLine(s);
        }

        static void Main(string[] args)
        {
            // C# 1.0
            TestGenericDelegate<int> testGenericDelA = new TestGenericDelegate<int>(GenericM);

            // C# 2.0
            TestGenericDelegate<string> testGenericDelB = delegate(string s) { System.Console.WriteLine(s); };

            // C# 3.0
            TestGenericDelegate<double> testGenericDelC = (x) => { System.Console.WriteLine(x); };

            // 调用委托.
            testGenericDelA(123456);
            testGenericDelB("That's nothing. I'm anonymous and ");
            testGenericDelC(123.456);

            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
    }
}

运行结果:

澳门葡京备用网址 26澳门葡京备用网址 27View Code

123456
That's nothing. I'm anonymous and
123.456
Press any key to exit.

 

// 声明一个委托,类型是myDelegate,
public delegate void myDelegate(string str); 
public static void HellowChinese(string strChinese) 
{ 
    Console.WriteLine("Good morning," + strChinese); 
    Console.ReadLine(); 
} 
// 实例化   
myDelegate d = new myDelegate(HellowChinese); 
// 使用
d("Mr wang");

二.二 引进匿名格局

  (1)首先,大家来看望上面包车型大巴事例怎么着选择匿超级模特式来促成:

DelegateTest dgTest2 = new DelegateTest(delegate(string name)

{

      Console.WriteLine("Good,{0}", name);

});

澳门葡京备用网址 28

从运维结果图中能够看看,原本须要传递方式名的地点大家一向传送了二个方法,那个方式以delegate(参数){方法体}的格式编写,在{}里边间接写了方法体内容。于是,大家禁不住喜气洋洋,又有啥不可简化一些工作量咯!

  (贰)其次,咱们将转移的次序通过Reflector反编写翻译看看匿名格局是怎么帮我们落实命名方式的功能的。

  1大家得以看到,在编写翻译生成的类中,除了大家温馨定义的方式外,还多了三个岂有此理的分子:

澳门葡京备用网址 29

  二由此逐一查看,原来编写翻译器帮大家转变了三个私家的嘱托对象以及三个私人住房的静态方法。大家能够大胆猜测:原来匿名方式不是从未有过名字的法子,如故生成了3个出名字的办法,只可是那一个艺术的名字被埋伏起来了,而且格局名是编写翻译器生成的。

澳门葡京备用网址 30

澳门葡京备用网址 31

  叁因此地点的分析,大家依然不甚了然,到底匿超级模特式委托对象在先后中是怎么展现的?那里,大家须要查阅Main方法,不过透过C#代码我们从未发现一些方可协助大家精通的。那时,大家想要刨根究底就有点麻烦了。幸好,在尧舜携阴挺,我们掌握能够借助IL(中间代码)来分析一下。于是,在Reflector中切换展示语言,将C#改为IL,就会看到其它1番领域。

澳门葡京备用网址 32

  (三)由地点的辨析,大家能够做出定论:编写翻译器对于匿名方式帮我们做了两件事,壹是生成了一个个体静态的信托对象和3个私家静态方法;二是将转移的办法的地点存入了信托,在运作时调用委托对象的Invoke方法执行该信托对象所独具的艺术。由此,大家也足以看到,匿名格局必要组合委托行使

委托


以示例 1 为例:

  • 声明(定义)委托

    delegate void TestDelegate(string s);

各类委托描述了主意签名和重临类型等任何细节。如 TestDelegate
定义方法有三个 string 类型的参数 s,并且重回 void 类型。

能够在任啥地点方定义委托,跟定义一个类类似。委托也可以有访问修饰符。

  • 实例化委托

    TestDelegate testdelA = new TestDelegate(M);

声称委托后,必须用某些方法实例化这些委托。用艺术 M 去实例化委托
testdelA

扬言(定义)和实例化委托,有点类似四个类,类也要求定义,并实例化。

信托在语法上,总是带有三个参数的构造函数,这些参数便是寄托引用的方法。也正是说,函数指针必须指向2个艺术。

  • 调用委托

    testdelA(“Hello. My name is M and I write lines.”);

实例化委托后,通过信托对象的称呼(前面是传递给委托的参数)调用委托对象。

信托也足以构成、移除,如下所示:

namespace MyDelegate

{

    delegate void D(int x);

 

    class C

    {

        public static void M1(int i)

        {

            Console.WriteLine("C.M1: " + i);

        }

        public static void M2(int i)

        {

            Console.WriteLine("C.M2: " + i);

        }

        public void M3(int i)

        {

            Console.WriteLine("C.M3: " + i);

        }

    }

}

用如下代码测试:

D cd1 = new D(C.M1);

cd1(-1);                // call M1

D cd2 = new D(C.M2);

cd2(-2);                // call M2

D cd3 = cd1 + cd2;

cd3(10);                // call M1 then M2

cd3 += cd1;

cd3(20);                // call M1, M2, then M1

C c = new C();

D cd4 = new D(c.M3);

cd3 += cd4;

cd3(30);                // call M1, M2, M1, then M3

cd3 -= cd1;             // remove last M1

cd3(40);                // call M1, M2, then M3

cd3 -= cd4;

cd3(50);                // call M1 then M2

cd3 -= cd2;

cd3(60);                // call M1

cd3 -= cd2;                // impossible removal is benign

cd3(60);                // call M1

cd3 -= cd1;                // invocation list is empty so cd3 is null

//        cd3(70);        // System.NullReferenceException thrown

cd3 -= cd1;                // impossible removal is benign
  • 用 Lambda 表明式创制和实例化委托。

    Func myFunc = x => x == 5;

    bool result = myFunc(4); // returns false of course

其中,Func<int, bool> 是.NET
提供的已打包好的嘱托,用于以参数情势传递的情势,必须重返值。那样,就毫无显式注明定义委托。该信托输入参数为
int,再次来到类型为 bool

 

寄托很好用。当编制程序到自然阶段,发现只传递2个或多少个int、strig类型参数是不够的,希望得以把1段代码进行传递来实施有些操作,委托提供了那般的门路,寄托提供了1种能够向来访问类中方法的途径,能够将艺术当作二个参数字传送递从而选取

二.叁 匿超级模特式扩充

  (1)匿名形式语法糖—越发简化你的代码

  在付出中,大家反复会动用语法糖来写匿名方式,例如下边所示:

        DelegateTest dgTest3 = delegate(string name)

        {

           Console.WriteLine("Goodbye,{0}", name);

        };

        dgTest3("Edison Chou");

  能够观看,使用该语法糖,将new
DelegateTest()也去掉了。可知,编译器让大家越来越轻松了。

  (2)传参也有大学问—向方法中传播匿超级模特式作为参数

  1在付出中,大家往往表明了一个方式,其参数是八个委托对象,可以接受任何符合委托定义的主意。

                    static
                            void InvokeMethod(DelegateTest dg)

    {

         dg("Edison Chou");

    }

  二我们能够将曾经定义的情势地址作为参数传入InvokeMethod方法,例如:InvokeMethod(TestFunc);
当然,大家也可以选择匿超级模特式,不需求独自定义就能够调用InvokeMethod方法。

    InvokeMethod(delegate(string name)

    {

          Console.WriteLine("Fuck,{0}", name);

    });

  (三)省略省略再省略—省略”大括号”

  经过编写翻译器的不止优化,我们发现连delegate后面包车型客车()都足以大致了,我们得以看看上边一段代码:

    InvokeMethod(delegate { 

         Console.WriteLine("I love C sharp!"); 

    });

  而作者辈事先的定义是如此的:

                    public
                            delegate
                                    void DelegateTest(string testName);

 

                    static
                            void InvokeMethod(DelegateTest dg)

        {

            dg("Edison Chou");

        }

  大家发现定义时办法是急需传递一个string类型的参数的,不过大家简要了deletegate后边的括号之后就未有参数了,那么结果又是什么样吗?经过调节和测试,发现结果输出的是:I
love C sharp!

  那时,大家就有点百思不得其解了!明明都未曾定义参数,为什么依然满意了适合委托定义的参数条件吧?于是,大家带着难题依旧借助Reflector去1探毕竟。

  一在Main函数中,能够看看编写翻译器为大家机关抬高了适合DelegateTest这些委托定义的章程参数,即二个string类型的字符串。固然,输出的是I
love C
sharp,但它的确是适合章程定义的,因为它会经受三个string类型的参数,即使在方法体中并未有采取到那一个参数。

澳门葡京备用网址 33

  ②正幸而Main函数中看出了匿名格局,现在能够看看编译器为大家所生成的命有名的模特式。

澳门葡京备用网址 34

.NET 提供的寄托


匿名函数

3、扩张方法:[ C# 叁.0/.NET 三.x 新增特色 ]

Action 委托

该信托以参数方式传递3个履行某操作的法子,不重临值。Action
委托有如下多少个重载:

  • Action 委托
  • Action<T> 委托
  • Action<T1, T2> 委托
  • Action<T1, T2, T3> 委托
  • Action<T1, T2, T3, T4> 委托

.NET framework ④.0 提供的重载越来越多。可提供 16 个输入参数。

示范 3:以 Action<T> 带1个参数的委托为例。

澳门葡京备用网址 35澳门葡京备用网址 36View Code

using System;

namespace MyAction
{
    class Program
    {
        // 声明委托
        delegate void DisplayMessage(string message);

        static void Main(string[] args)
        {
            // 用 ShowWindowsMessage,采用命名方法实例化 DisplayMessage 委托
            DisplayMessage messageTargetA = new DisplayMessage(ShowWindowsMessage);
            DisplayMessage messageTargetB = ShowWindowsMessage;
            // 用 ShowWindowsMessage,采用命名方法实例化 Action 委托
            Action<string> messageTargetC = ShowWindowsMessage;
            // 用 ShowWindowsMessage,采用匿名方法实例化 Acton 委托
            Action<string> messageTargetD = delegate(string s) { ShowWindowsMessage(s); };
            // 用 ShowWindowsMessage,采用 Lambda 表达式实例化 Acton 委托
            Action<string> messageTargetE = s => ShowWindowsMessage(s);

            messageTargetA("Hello, World!");
            messageTargetB("Hello, World!");
            messageTargetC("Hello, World!");
            messageTargetD("Hello, World!");
            messageTargetE("Hello, World!");
            System.Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
        private static void ShowWindowsMessage(string message)
        {
            System.Console.WriteLine(message);
        }
    }
}

运营结果:

澳门葡京备用网址 37澳门葡京备用网址 38View Code

Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Press any key to exit.

该示例最简便易行的花样也可写成:

澳门葡京备用网址 39澳门葡京备用网址 40View Code

Action<string> messageTarget = s => System.Console.WriteLine(s);
messageTarget("Hello, World!");
System.Console.WriteLine("Press any key to exit.");
Console.ReadKey();

地点已经讲到匿名函数了。函数和办法等价,用来封装一段代码片以便随时使用,有的有再次回到值有的无再次回到值。写在类里面。

三.一 神奇—初玩扩充方法

  (一)提到扩充方法,小编想超越八分之四的园友都不素不相识了。可是依然来探望MSDN的定义:

MSDN
说:
扩张方法使您能够向现有项目“添加”格局,而无需成立新的派生类型、重新编写翻译或以别的措施修改原始类型。那里的”添加”之所以选取引号,是因为并不曾真的地向钦定项目丰硕方法。

  那么,有时候大家会问:缘何要有扩展方法吗?那边,大家得以顾名思义地想转手,扩张扩充,那么一定是事关到可增添性。在架空工厂情势中,大家得以由此新增3个工厂类,而不供给更改源代码就足以切换来新的工厂。这里也是那般,在不修改源码的动静下,为有个别类增加新的方式,也就落实了类的扩充。

  (二)空说无凭,大家来看看在C#中是怎么来判定扩大方法的:通过智能提示,大家发现有局地方法带了3个针对下方的箭头,查看”温馨提醒”,大家领略她是三个恢弘方法。所得是乃,原来笔者们一向对聚集举办筛选的Where()办法依然是扩大方法而不是原生的。

澳门葡京备用网址 41

  我们再来看看使用Where这一个扩张方法的代码示例:

澳门葡京备用网址 42)

                    static
                            void UseExtensionMethod()

        {

            List<Person> personList = new List<Person>()

            {

                    new Person(){ID=1,Name="Big Yellow",Age=10},

                    new Person(){ID=2,Name="Little White",Age=15},

                    new Person(){ID=3,Name="Middle Blue",Age=7}

            };

 

                        // 下面就使用了IEnumerable的扩展方法:Where


                    var datas = personList.Where(delegate(Person p)

            {

                    return p.Age >= 10;

            });

 

                    foreach (var data in datas)

            {

                Console.WriteLine("{0}-{1}-{2}", 

                    data.ID, data.Name, data.Age);

            }

        }

澳门葡京备用网址 43)

  上述代码应用了Where扩大方法,找出集合中Age>=10的多寡形成新的数据集并出口:

澳门葡京备用网址 44

  (三)既然扩张方法是为了对类举行扩展,那么大家行不行拓展自定义扩张呢?答案是必须能够。大家先来探望扩充方法是何等的概念的,可以经过刚刚的IEnumerable接口中的Where方法定义来探视有啥样规则:通过
转到定义
的点子,大家得以看看在System.Linq命名空间下,有号称Enumerable的那样一个静态类,它的分子方法全是静态方法,而且每一个方法的绝大部分第一参数都是以this开首。于是,大家得以总括出,增加方法的八个要素是:静态类静态方法以及this关键字

                    public
                            static
                                    class Enumerable

    {

                    public
                            static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer);

    }

  那么难题又来了:为啥一定得是static静态的呢?那几个大家都领会静态方法是不属于有个别类的实例的,也便是说大家不必要实例化那个类,就足以访问那一个静态方法。所以,你懂的哇。

  (4)看完增添方法3要素,大家就来机关动手写一个扩充方法:

澳门葡京备用网址 45)

                    public
                            static
                                    class PersonExtension

    {

                    public
                            static
                                    string FormatOutput(this Person p)

        {

                    return
                            string.Format("ID:{0},Name:{1},Age:{2}",

                p.ID, p.Name, p.Age);

        }

    }

澳门葡京备用网址 46)

  上边这些扩张方法成功了一个格式化输出Person对象属性音讯的字符串构造,能够完结地方例子中的输出效果。于是,大家得以将地点的代码改为以下的法子进行输出:

澳门葡京备用网址 47)

                    static
                            void UseMyExtensionMethod()

        {

            List<Person> personList = new List<Person>()

            {

                    new Person(){ID=1,Name="Big Yellow",Age=10},

                    new Person(){ID=2,Name="Little White",Age=15},

                    new Person(){ID=3,Name="Middle Blue",Age=7}

            };

 

                    var datas = personList.Where(delegate(Person p)

            {

                    return p.Age >= 10;

            });

 

                    foreach (var data in datas)

            {

                Console.WriteLine(data.FormatOutput());

            }

        }

澳门葡京备用网址 48)

Func 委托

该信托以参数格局传递的法门,必须重回值。Func 委托有如下几个重载:

  • Func<TResult> 委托
  • Func<T, TResult> 委托
  • Func<T1, T2, TResult> 委托
  • Func<T1, T2, T3, TResult> 委托
  • Func(<T1, T2, T3, T4, TResult> 委托

.NET framework 肆.0 提供的重载越来越多。可提供 1陆 个输入参数。

示范 四:以 Func(T, TResult) 待八个参数的寄托为例。

澳门葡京备用网址 49澳门葡京备用网址 50View Code

using System;

namespace MyFunc
{
    delegate string ConvertMethod(string inString);

    class Program
    {
        static void Main(string[] args)
        {
            // 用 UppercaseString,以命名方法实例化委托
            ConvertMethod convertMethA = UppercaseString;
            // 用 UppercaseString,以命名方法实例化 Func 委托
            Func<string, string> convertMethB = UppercaseString;
            // 以匿名方法实例化 Func 委托
            Func<string, string> convertMethC = delegate(string s) { return s.ToUpper(); };
            Func<string, string> convertMethD = delegate(string s) { return UppercaseString(s); };
            // 以 Lambda 表达式实例化  Func 委托
            Func<string, string> convertMethE = s => s.ToUpper();

            System.Console.WriteLine(convertMethA("Dakota"));
            System.Console.WriteLine(convertMethB("Dakota"));
            System.Console.WriteLine(convertMethC("Dakota"));
            System.Console.WriteLine(convertMethD("Dakota"));
            System.Console.WriteLine(convertMethE("Dakota"));

            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
        private static string UppercaseString(string inputString)
        {
            return inputString.ToUpper();
        }
    }
}

运作结果:

澳门葡京备用网址 51澳门葡京备用网址 52View Code

DAKOTA
DAKOTA
DAKOTA
DAKOTA
DAKOTA
Press any key to exit.

该示例最简单易行的款式也可写成:

澳门葡京备用网址 53澳门葡京备用网址 54View Code

Func<string, string> convertMeth = s => s.ToUpper();
System.Console.WriteLine(convertMeth("Dakota"));
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();

不过假诺小编只想把那段代码片使用三次啊?再声称三个类、2个艺术其实太麻烦,那时候匿名函数就全体了市场股票总值。用来封装1段代码、直接执行只怕传递。

叁.二 嗦嘎—探秘扩大方法

  刚刚大家感受了扩大方法的神奇之处,现在大家针对刨根究底的学习态度,借助Reflector看看编写翻译器到底帮我们做了什么样工作?

  (壹)通过反编写翻译刚刚那四个UseMyExtensionMethod方法,大家发现并从未什么样意外之处。

  (二)那时,大家得以将C#切换来IL代码看看,恐怕会有另一番到手?于是,果断切换之后,发现了真理!

澳门葡京备用网址 55

  原来编写翻译器在编写翻译时自动将Person.FormatOutput更改为了PersonExtension.FormatOutput,那时大家好像发聋振聩,所谓的扩展方法,原来正是静态方法的调用而已,所德是乃(原来是那样)!于是,我们可以将如此认为:person.FormatOutput()
等同于调用 PersonExtension.FormatOutput(person);

  (叁)再查看所编写翻译生成的措施,发现this关键已经消失了。我们情不自尽一声惊讶,原来this只是二个符号而已,标记它是扩张的是哪四个项目,在方法体中得以对那么些类其他实例进行操作。

澳门葡京备用网址 56

Predicate 委托

该信托定义1组条件并规定钦点对象是或不是相符这几个标准的格局。此委托由 Array
和 List<T> 类的两种艺术应用,用于在联谊中搜索成分。

演示 伍:演示在数组中追寻第2个 X*Y>100000 的点。

澳门葡京备用网址 57澳门葡京备用网址 58View Code

using System;
using System.Collections.Generic;

namespace MyPredicate
{
    class Program
    {
        static void Main(string[] args)
        {
            Point[] points = { 
                                 new Point(){X = 100,Y = 200}, new Point(){X = 150,Y = 250}, 
                                 new Point(){X = 250,Y = 375}, new Point(){X = 275,Y = 395}, 
                                 new Point(){X = 295,Y = 450}, new Point(){X = 290,Y = 451}
                             };

            Point first = Array.Find(points, ProductGT10);
            Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
        class Point
        {
            public int X { get; set; }
            public int Y { get; set; }
        }
        private static bool ProductGT10(Point p)
        {
            if (p.X * p.Y > 100000)
                return true;
            else
                return false;
        }
    }
}

也得以那个写:

澳门葡京备用网址 59澳门葡京备用网址 60View Code

Point[] points = { 
                     new Point(){X = 100,Y = 200}, new Point(){X = 150,Y = 250}, 
                     new Point(){X = 250,Y = 375}, new Point(){X = 275,Y = 395}, 
                     new Point(){X = 295,Y = 450}, new Point(){X = 290,Y = 451}
                 };

Point first = Array.Find(points,
    (p) =>
    {
        if (p.X * p.Y > 100000)
            return true;
        else
            return false;
    });
Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();

证实:无需出示创设委托,或是钦命泛型方法的参数类型,因为编写翻译器会依照上下文本人分明。

 

匿名函数总是和委托1起使用,因为匿名函数方便了委托的采用(不用声美素佳儿(Friso)(Karicare)个类了)

三.三 注意—总计扩大方法

  (1)怎样定义扩张方法:

  定义静态类,并添加public的静态方法,第一个参数
代表 扩大方法的扩张类。

  a)
它必须放在一个非嵌套、非泛型的静态类中(的静态方法);

  b)
它至少有2个参数;

  c)
第1个参数必须叠加 this 关键字;

  d)
第一个参数不可能有其余别的修饰符(out/ref)

  e)
第贰个参数无法是指针类型

  (2)当大家把扩张方法定义到任何程序集中时,一定要小心调用扩大方法的环境中须要包蕴扩大方法所在的*取名空间*!

  (三)假若要增添的类中本来就有和扩张方法的称呼相同的章程,到底会调用成员方法或许扩充方法吗?

答案:编写翻译器暗中认可认为三个表明式是要使用一个实例方法,但要是没有找到,就会检讨导入的命名空间和当前定名空间里有着的壮大方法,并合作到符合的章程。

参考资料

 


  • MSDN
    申明、实例化和平运动用委托.aspx) 
  • MSDN
    提供的信托 
  • 事件(C#
    编制程序指南)澳门葡京备用网址 ,.aspx)
  • 委托(C#
    编制程序指南).aspx)
  • C# 3.0 Cookbook, Third Edition: More than 250 solutions for C#
    3.0 programmers-Delegates, Events, and Lambda
    Expressions
  • C# 3.0: Master the fundamentals of C# 3.0-Delegates and
    Events
  • 程序设计_猫老鼠主人

 

匿超级模特式二种达成格局:

 

 

修改记录


  • 2015年1月29日 【UPDATE】

 

下载 Deom

下载愈来愈多 德姆o

使用Lambda表达式:

1.1 初识Action

MSDN付出的定义:包裹2个办法,该办法不持有参数并且不重回值

  能够选拔此委托以参数情势传递格局,而不用显式评释自定义的嘱托。封装的艺术必须与此委托定义的艺术签名相对应。也正是说,封装的不2诀窍不得持有参数,并且不得重返值。(在
C# 中,该办法必须重返 void)常常,那种格局用于实施有个别操作。

  未来,我们来看看哪些行使Action委托:

  (1)先看看后边大家是怎么来利用无再次来到值委托的事例:

澳门葡京备用网址 61 View Code

  能够领略地看出,大家事先要先显式注明了2个名称为 ShowValue
的嘱托,并将对 Name.DisplayToWindow 实例方法的引用分配给其委托实例。

  (二)再看看有了Action委托随后大家怎么来实现地点的效率的例证:

澳门葡京备用网址 62 View Code

  能够知道地看出,未来选用 Action
委托时,不必显式定义二个包装无参数进度的信托。

        public delegate void Seep();
        static void Main(string[] args)
        {

            Seep s = () => { Console.WriteLine(2); Console.WriteLine(1); };
        }

1.2 深入Action

  在实际支付中,大家日常将一个寄托实例作为叁个措施的参数实行传递,于是大家来看一下这几个天下第2的情景,再经过Reflector反编写翻译工具查看编译器到底帮大家做了怎么样逸事情!

  (一)首先来看一下在List集合类型的ForEach方法的概念:

澳门葡京备用网址 63)

                    //


                        // 摘要:

        //     对 System.Collections.Generic.List<T> 的每个元素执行指定操作。


        //


                        // 参数:

        //   action:

        //     要对 System.Collections.Generic.List<T> 的每个元素执行的 System.Action<T> 委托。


        //


                        // 异常:

        //   System.ArgumentNullException:

        //     action 为 null。


                        public
                                void ForEach(Action<T> action);

澳门葡京备用网址 64)

  能够看出,ForEach方法的参数是3个Action委托实例,也正是说是一个无重返值的信托实例。

  (二)定义二个实体类,并经过Action委托行使ForEach方法:

澳门葡京备用网址 65 View Code

  能够看出,大家为ForEach方法传递了贰个Action委托的实例,本质上是3个无重临值的章程指针,遍历输出了种种Person对象的音信。

  澳门葡京备用网址 66

  (3)也许某些童鞋看到地点的照旧有点不解,只要你打探过委托,那么大家得以透过Reflector反编写翻译工具去探访编译器到底做了啥事,Action委托的黄山真面目就会1如精通:(这里大家得以先看看未有Action的做法,是还是不是亟需首先显式表明了1个无重回值的寄托,然后是还是不是还要顶1个命名的无再次回到值的点子?)

  壹将编写翻译好的次序集拖动到Reflector中,可以观望以下的情形:

澳门葡京备用网址 67

  2现在独家看看编写翻译器为大家自动生成的无重回值的信托定义和方法定义:

澳门葡京备用网址 68

澳门葡京备用网址 69

  能够看出,不管是自动生成的信托依旧艺术,都是不带重回值的。

  3有了位置的解析,大家再来看看执行的言辞是怎么被编写翻译的:

澳门葡京备用网址 70

   能够见见,在编写翻译后的代码里边连new
Action<Person>()都省掉了,大家也足以精通,在代码中能够尤其简化。不过,首先,大家得询问到底编写翻译器是怎么识别Action委托的。于是,依据前两篇的思路,在反编写翻译后的C#代码看不出什么线索的时候,切换来IL代码壹探终究:

澳门葡京备用网址 71

  由IL代码可以看出,依然原本的法子,如故原先的含意。委托依旧那些委托,执行委托仍旧履行这些格局。那里,大家再来看看List类型的ForEach方法是怎么使用Action委托的:

澳门葡京备用网址 72

  今后,大家得以知晓,原来所不解的东西未来毕竟放心了:在ForEach会通过3个循环遍历依次调用委托所兼有的主意,那些主意是三个相符Action委托定义的无再次来到值方法。至于,为何大家能够归纳new
Action<T>(),则是编写翻译器为大家提供的一个有利于。例如,大家在使用List<Person>对象的ForEach方法时,我们得以那样写:

personList.ForEach(delegate(Person p)

{

      Console.WriteLine(p.ID + "-" + p.Name + "-" + p.Age);

});

  首先,由于大家是利用的personList这些目的(List<Person>类型),所以编写翻译器自动识别了泛型委托的T(即内定项目)为Person。其次,编写翻译器自动将无重临值的匿名情势转换为了new
Action<Person>对象。当然,若是是有重返值的匿名格局则会转移为内定项目标new
Func<T>()对象,那里因为ForEach只接受无参数的嘱托实例或措施,所以一旦传入了有重临值的匿名方式则会报错。

采纳委托

一.三 你毕竟有多少个Action可用?

澳门葡京备用网址 73
  从图中可以看到,.NET
Framework为我们提供了多达十五个参数的Action委托定义,对于广泛的支付情况已经完全够用了。

 

2、有重返类型的嵌入委托—Func

        public delegate void Seep();
        static void Main(string[] args)
        {
            Seep see = delegate () { Console.WriteLine(1); };
        }

2.1 初识Func

MSDN付给的概念:装进一个负有三个参数并回到 TResult
参数内定的类型值的不贰秘籍

  此委托的概念如下:

public
                            delegate TResult Func<in T, out TResult>(T arg)

  (一)in T
:此委托封装的主意的参数类型。

  (二)out
TResult :此委托封装的艺术的回到值类型。

  可以选拔此委托代表一种能以参数情势传递的主意,而不用显式表明自定义委托。封装的章程必须与此委托定义的章程签名相呼应。也便是说,封装的措施必须具有2个经过值传递给它的参数,并且必须再次回到值。

 

  贰.壹.一 未有Func时的行使

澳门葡京备用网址 74 View Code

Action、Func、Predicate

  贰.一.贰 有了Func后的应用

澳门葡京备用网址 75 View Code

  当然,大家还能依靠匿超级模特式特别简便易行地行使:

澳门葡京备用网址 76 View Code

  能够通晓地看出,未来采取 Func
委托时,不必显式定义1个新委托并将命名形式分配给该信托。

信托需求先声澳优(Ausnutria Hyproca)个连串才能使用,那很费劲,比如我在某二个命名空间表明了1个未曾重返值的委托myDelegate,然后想要那些委托的时候,各样命名空间都要引用这么些命名空间,那太不团结了。

2.2 深入Func

微软平素就在框架中概念了三种委托:Action、Func、Predicate。那两种委托是C#的System命名空间中早就定义好的,如Action

  二.2.一 用法先行:爽一下

  大家早已知道Func委托是带内定重临值类型的寄托,那么大家来探望在实际上费用境况的一幕。仍旧以刚刚那么些数据集合PersonList为例,在广大时候大家必要对从数据库中读取的数码集合进行一回筛选,那时大家能够应用List集合的Select方法,大家将二个Func委托实例作为艺术参数字传送递给Select方法,就能够回到三个合乎大家钦赐条件的新数据集合。

  (1)先来看望Select方法的概念:

澳门葡京备用网址 77)

                    //


                        // 摘要:

        //     将序列中的每个元素投影到新表中。


        //


                        // 参数:

        //   source:

        //     一个值序列,要对该序列调用转换函数。


        //


                    //   selector:

        //     应用于每个元素的转换函数。


        //


                        // 类型参数:

        //   TSource:

        //     source 中的元素的类型。


        //


                    //   TResult:

        //     selector 返回的值的类型。


        //


                        // 返回结果:

        //     一个 System.Collections.Generic.IEnumerable<T>,其元素为对 source 的每个元素调用转换函数的结果。


        //


                        // 异常:

        //   System.ArgumentNullException:

        //     source 或 selector 为 null。


                        public
                                static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

澳门葡京备用网址 78)

  能够见到,Select方法中的参数选拔了Func泛型委托,依照泛型委托的定义TSource和TResult分别表示要传播的数据类型以及要回去的数据类型。

  (二)再来看看哪些在先后中选择Func委托:

  首先定义八个与源数据类型差别的新数据类型作为再次回到值类型:

                    public
                            class LitePerson

    {

                    public
                            string Name { get; set; }

    }

  壹正式定义版:

澳门葡京备用网址 79)

            List<Person> personList = GetPersonList();

 

            IEnumerable<LitePerson> litePersonList = personList.Select<Person, LitePerson>(

                    new Func<Person, LitePerson>

                (

                    delegate(Person p)

                    {

                    return
                            new LitePerson() { Name = p.Name };

                    }

                )

            );    

澳门葡京备用网址 80)

  二哟哈简化版:借助理编辑译器提供的自动识别,简化大家的代码

            IEnumerable<LitePerson> litePersonList = personList.Select(

                    delegate(Person p)

                {

                    return
                            new LitePerson() { Name = p.Name };

                }

            );

  3绝逼懒人版:借助匿名类和泛型可以大大简化大家的代码

                    var liteList = personList.Select(delegate(Person p)

            {

                    return
                            new { Name = p.Name, AddDate = DateTime.Now };

            });

  (3)调节和测试运维可以赢得以下结果:

澳门葡京备用网址 81

澳门葡京备用网址 82

  二.二.2 原理为王:探1回

  (一)通过Reflector反编写翻译,大家再来看看编写翻译器帮大家转变的东东:

澳门葡京备用网址 83

  (二)看看自动生成的寄托和格局的概念:

澳门葡京备用网址 84

澳门葡京备用网址 85

  相信通过上节Action的详细分析,这里大家应该也足以举①反三精晓编写翻译器帮我们毕竟做了怎么事情了,那里笔者就不再赘述了,前面也不会再赘述此方面包车型大巴东东(为了节省页面大小)。

  当然,和Action类似,.NET基类库为大家也提供了多达16个输入参数的Func委托,可是,输出参数却只有1个。

上边已经由此匿名函数实现了不用证明类,今后经过C#预约义的嘱托项目达成了永不表明委托项目,那么今后就足以一向写代码片来施行了

叁、重返bool类型的放权委托—Predicate

那三种委托的对应泛型情势,能够写出如下代码:

3.1 初识Predicate

  经过了Func的摸底,大家能够清楚接下去的那七个Predicate和Comparison其实都属于有再次来到值类型的委托,他们只是是五个有血有肉的奇异实例而已(1个回来bool类型,八个回来int类型)。

MSDN付出的定义:表示定义1组条件并明确钦定对象是不是吻合那些原则的法子

  它的概念相当粗略:(那里就不再对其进展分解了)

public
                            delegate
                                    bool Predicate<in T>(T obj)

  此委托由 Array
和 List<T> 类的二种艺术应用,常用来在聚集中搜索成分。

            #region 无参数无返回值
            // lambda实现委托实例
            Action a1 = () => Console.WriteLine(1);
            a1();
            // delegate实现委托实例,下面不再演示delegate。
            Action a2 = delegate { Console.WriteLine(1); };
            a2();
            #endregion

            #region 有参数无返回值
            Action<int> a3 = (x) => Console.WriteLine(x);
            a3(1);
            #endregion

            #region 无参数有返回值的情况
            Func<int> e1= ()=> 1;
            var value1= e1();
            #endregion

            #region 有参数有返回值的情况
            // 最后一个泛型是返回值的类型
            Func<int,int> e2 = (x) => x+1;
            int value2= e2(1);
            // 多参数情况
            Func<int, int,int> e3 = (x,x2) => x+x2 + 1;
            int value3 = e3(1,2);
            #endregion

            #region 返回值是布尔类型
            // 其实Predicate可以用Func返回值是bool来代替的。
            Predicate<int> p = (x) => x > 0;
            bool value4 = p(1);
            #endregion

3.2 深入Predicate

  由于Predicate委托常用于在集聚中搜索成分,那么我们就来看望哪些行使Predicate委托来拓展成分的探寻。于是,大家将目光转到List集合的FindAll方法,相信超过四分之二童鞋都用过那些主意。

  (一)先来看望FindAll的定义:

澳门葡京备用网址 86)

                    //


                        // 摘要:

        //     检索与指定谓词定义的条件匹配的所有元素。


        //


                        // 参数:

        //   match:

        //     System.Predicate<T> 委托,用于定义要搜索的元素应满足的条件。


        //


                        // 返回结果:

        //     如果找到,则为一个 System.Collections.Generic.List<T>,其中包含与指定谓词所定义的条件相匹配的所有元素;否则为一个空


        //     System.Collections.Generic.List<T>。


        //


                        // 异常:

        //   System.ArgumentNullException:

        //     match 为 null。


                        public List<T> FindAll(Predicate<T> match);

澳门葡京备用网址 87)

  (二)再来看看FindAll的兑现:

澳门葡京备用网址 88

  (3)今后大家来用一下Predicate委托:依然以老大PersonList集合为例,假使我们要筛选出Age>20的Person,大家就能够动用FindAll方法。今后大家来写一下以此委托:(前面大家会用拉姆da表明式来简写,那才叫3个爽!)能够看到,关键点在于:delegate(Person
p) { return p.Age > 20;
}
这一句上,传入参数是Person类型的对象,再次回到的是一个相比结实即bool值。

澳门葡京备用网址 89 View Code

信托还有一对本性(如可加性),感兴趣的能够查看有关资料。

四、再次来到int类型的放置委托—Comparison

Expression

4.1 初识Comparison

MSDN提交的定义:意味着相比一致类型的八个指标的点子

  它的概念也很简短:

public
                            delegate
                                    int Comparison<in T>(T x, T y)

  T是要比较的目的的档次,而再次来到值是二个有标志整数,提醒 x
与 y 的相对值,如下表所示:

含义

小于 0

x 小于 y。

0

x 等于 y。

大于 0

x 大于 y。

  此委托由 Array
类的 Sort<T>(T[],
Comparison<T>) 方法重载和 List<T> 类的 Sort(Comparison<T>) 方法重载使用,用于对数组或列表中的成分实行排序

Expression指的是System.Linq.Expressions,是Linq表明式,表明式树,不是Lambda表达式!!

4.2 深入Comparison

  由于Comparison委托常用于在集合中开展排序,那么我们就来看看怎么着利用Comparison委托来进展成分的排序。于是,大家将目光转到List集合的Sort方法,相信当先四分之二童鞋也都用过这几个格局。

  (一)老惯例,如故先看看Sort方法的概念:

澳门葡京备用网址 90)

                    //


                        // 摘要:

        //     使用指定的 System.Comparison<T> 对整个 System.Collections.Generic.List<T> 中的元素进行排序。


        //


                        // 参数:

        //   comparison:

        //     比较元素时要使用的 System.Comparison<T>。


        //


                        // 异常:

        //   System.ArgumentNullException:

        //     comparison 为 null。


        //


                    //   System.ArgumentException:

        //     在排序过程中,comparison 的实现会导致错误。
                    例如,将某个项与其自身进行比较时,comparison 可能不返回 0。


                        public
                                void Sort(Comparison<T> comparison);

澳门葡京备用网址 91)

  (二)再来看看Sort方法的兑现:

澳门葡京备用网址 92

  能够见到,那里纵然使用Comparison委托但最终仍旧转换到了Comparer相比较器,又一次调用重载的Array.Sort静态方法实行排序。

澳门葡京备用网址 93

  (3)以往我们来用一下Comparison委托:照旧以十二分PersonList集合为例,若是大家要以Age为尺度进行降序排列,大家理应怎么来写这些委托呢?

澳门葡京备用网址 94 View Code

  落成的成效如下图所示:

澳门葡京备用网址 95

  那么,即便是要开始展览升序排列呢?只要求改一下:return
p二.Age-p1.Age; 更改一下被减数和减数的岗位,即可到位升序和降序的切换。

澳门葡京备用网址 96 View Code

澳门葡京备用网址 97

Linq表明式用于离线集合的查询。什么是离线集合?最常用的是EF里面包车型地铁DBContext,笔者也只用过这几个,所以自个儿不想那么多,就把Expression当成EF里面使用的就行了。

五、Lambda表达式:[ C# 叁.0/.NET 3.x 新增特色 ]

  回想,发现下边包车型客车代码,须要传3个匿名方法
,写起来尤其别扭。于是大家很想清楚可不可以有简化的语法呢?微软告知我们:Of
Course,必须有,它正是Lambda表明式。Lambda表明式是比匿名情势更简洁的一种匿名方式语法。

Lambda来源:一九二零年到一玖二七年之间,地法学家Alonzo
丘奇等人表达了Lambda积分。Lambda积分是用来表示函数的1套系统,它应用希腊共和国(Ελληνική Δημοκρατία)字母Lambda(λ)来表示无名函数。近期,函数式编程语言(如Lisp)使用那个术语来代表能够直接描述函数定义的表达式,表明式不再供给知名字了。

一、只好接受拉姆da表明式表示的委托

5.1 初识Lambda表达式澳门葡京备用网址 98  伍.一.壹 Lambda表明式要点

    1Lambda表明式中的参数列表(参数数量、类型和职位)必须与信托相相配

    2表明式中的参数列表不必然供给包罗类型,除非委托有ref或out关键字(此时必须出示注解);

    ③假设未有参数,必须接纳1组空的圆括号

2、Lambda表达式只好有一条语句。

  5.1.2 Lambda使用示例

澳门葡京备用网址 99 View Code

   调节和测试运营的结果如下:

澳门葡京备用网址 100

            Expression<Func<int,int>> eeee = (x)=> x+ 1 ;

  5.1.叁 拉姆da本质探析

  (一)以上述案例中的Sort方法为例:personList.Sort((p1,
p2) => p1.Age – p2.Age);

  (二)通过反编写翻译工具,能够看出实际是声称了1个Comparison委托实例:

澳门葡京备用网址 101

  (三)今后,大家来分析一下切实的步凑:有了前面包车型大巴根基,以往再来看就自在了许多,So
Easy!

    一编写翻译器自动生成了三个Comparison委托:

澳门葡京备用网址 102

    二编写翻译器帮大家创建了3个顺应Comparison委托签名的静态方法:

澳门葡京备用网址 103

    3实例化Comparison委托变量,并将艺术指针传入该信托;

    肆调用List<T>实例的Sort方法,并传播Comparison委托实例;

    个中,前面两步壹和2得以经过反编写翻译后的C#代码获知,而背后两步3和四则需要通过IL代码来分析,前边早已介绍过相关,那里就不再赘述。

总结

一、都以指望得以独立引用壹段代码片引起的。
2、然后引用了信托delegate,delegate的施用方法为注明类型-实例化类型(传入想要使用的类的主意)-使用委托(使用办法)
三、简化操作,使用(通过Lambda或然delegate)匿名方式来直接声雅培(Abbott)(Nutrilon)(Beingmate)段代码片,防止注解所想使用的类的诀要
四、简化操作,间接使用C#预约义的二种委托Action、Func、Predicate,连注解委托都省了。
五、本文代码:

5.2 回顾Lambda进化史

  前边理解了拉姆da是怎么,那里大家来回看一下Lambda的演化进程。澳门葡京备用网址 104

  从演化进度可以掌握,编写翻译器在越来越智能地帮大家做着更加多的事体,而小编辈却在分享着编写翻译器带来的造福沉浸在连忙的支出功能中,变得愈加”懒”了。

注意

壹、匿名函数总是和委托一起使用(两种预约义委托)
贰、使用二种预约义委托就足以满足大多数急需。
三、Expression是Linq表明式树,只好选用接受一句lambda表明式。和匿名函数非亲非故。

5.3 语句Lambda

  Lambda表明式有三种档次:壹是拉姆da表明式,二是语句拉姆da。澳门葡京备用网址 105

  那么,语句Lambda和表明式Lambda到底有什么区别?

ANSWER:语句Lambda 和
表明式Lambda 的界别在于,前者在
=>左边有1个语句块(大括号),而后人唯有一个表明式(未有return
和大括号)。

EXAMPLES:

(1)表达式Lambda:

list.FindAll(d => d.Id > 2);// goes to


list.ForEach(d => Response.Write(d.ToString() + "<br/>"));

(2)语句Lambda:

list.ForEach(d => { if (d.Id > 2) { Response.Write(d.ToString() + "<br/>"); } });

  可以看来,语句拉姆da的出手有一个语句块,在那个大括号内的言辞也许会有多条。

 

 

 

 

 

 标准查询运算符提供了席卷筛选、投影、聚合、排序等职能在内的询问功效,其本质是概念在System.Linq.Enumerable类中的50多个为IEnumerable<T>准备的扩大方法

澳门葡京备用网址 106

  从上海教室能够看看,在Enumerable类中提供了多如牛毛的增加方法,那里大家选取中间几个最常用的方法来作一点介绍,使大家能更加好地使用它们。首先,我们须求或多或少数码来进行出现说法:

澳门葡京备用网址 107 View Code

1.壹 筛选高手Where方法

  Where方法提供了大家对此叁个集结的筛选作用,但须求提供三个带bool重回值的”筛选器“(匿名格局、委托、拉姆da表达式均可),从而评释集合中有些成分是不是相应被重回。那里,大家以地方的数额为例,筛选出集合中颇具性别为男,年龄超越20岁的子集合,借助Where方法完结如下:

澳门葡京备用网址 108)

                    static
                            void SQOWhereDemo()

        {

            List<Person> personList = GetPersonList();

 

            List<Person> maleList = personList.Where(p =>

                p.Gender == true && p.Age > 20).ToList();

            maleList.ForEach(m => Console.WriteLine(m.ToString()));

        }

澳门葡京备用网址 109)

  (一)运营结果如下图所示:

澳门葡京备用网址 110

  (二)由本种类文章的第3篇可见,扩充方法的真相是在运维时调用扩充类的静态方法,而作者辈写的Lambda表达式在编写翻译时又会被转为匿名方式(准确地说应该是预订义泛型委托实例)作为艺术参数字传送入扩充方法中,最终调用执行该扩张方法生成3个新的List集合重回。

一.二 投影大牌Select方法

  Select方法能够查询投射,重返新目的集合。那里,假若大家先筛选出具有男性集合,再依据男性集合中有所项的姓名生成子集合(这是四个差异于原项目标项目),就能够借助Select方法来兑现。

澳门葡京备用网址 111)

                    static
                            void SQOSelectDemo()

        {

            List<Person> personList = GetPersonList();

 

            List<LitePerson> liteList = personList.Where(p =>

                p.Gender == true).Select(

                p => new LitePerson() { Name = p.Name }).ToList();

            liteList.ForEach(p => Console.WriteLine(p.ToString()));

        }

澳门葡京备用网址 112)

  (1)运转结果如下图所示:

澳门葡京备用网址 113

  (二)那里也足以利用匿名类,能够省去事先申明LitePerson类的步凑,但供给相称var使用:

var annoyList = personList.Where(p =>

    p.Gender == true).Select(

    p => new { Name = p.Name }).ToList();

  (3)那里因为达成LitePerson类重写了ToString()方法,所以那边一贯调用了ToString()方法。

壹.3 排序小生OrderBy方法

  提起排序,我们立时想起了SQL中的order
by语句,而正规查询运算符中也为大家提供了OrderBy这些主意,值得壹提的正是大家得以开展多规格的排序,因为OrderBy方法重临的照旧是二个IEnumerable<T>的档次,还是可以继承应用增加方法。但要注意的是,第四回应该利用ThenBy方法。

澳门葡京备用网址 114)

                    static
                            void SQOOrderByDemo()

        {

            List<Person> personList = GetPersonList();

                        // 单条件升序排序


            Console.WriteLine("Order by Age ascending:");

            List<Person> orderedList = personList.OrderBy(p => p.Age).ToList();

            orderedList.ForEach(p => Console.WriteLine(p.ToString()));

                        // 单条件降序排序


            Console.WriteLine("Order by Age descending:");

            orderedList = personList.OrderByDescending(p => p.Age).ToList();

            orderedList.ForEach(p => Console.WriteLine(p.ToString()));

                        // 多条件综合排序


            Console.WriteLine("Order by Age ascending and ID descending:");

            orderedList = personList.OrderBy(p => p.Age)

                .ThenByDescending(p => p.ID).ToList();

            orderedList.ForEach(p => Console.WriteLine(p.ToString()));

        }

澳门葡京备用网址 115)

  启动结果如下图所示:

澳门葡京备用网址 116

壹.四 连接道士Join方法

  在数据库中,大家对三个表或三个表举行连接查询时频仍会用到join语句,然后内定五个表之间的涉及关系(例如:
a.bid =
b.aid)。在正儿八经查询运算符中,细心的.NET基类库也为大家提供了Join方法。未来,假诺大家有多少个类:Person和Children,当中各种Children对象都有三个ParentID,对应Person对象的ID,现须求打字与印刷出富有Person和Children的新闻,能够借助Join方法来贯彻。

澳门葡京备用网址 117)

                    static
                            void SQOJoinDemo()

        {

            List<Person> personList = GetPersonList();

            List<Children> childrenList = GetChildrenList();

 

                        // 连接查询


                    var joinedList = personList.Join(childrenList,

                p => p.ID, c => c.ParentID, (p, c) => new


                {

                    ParentID = p.ID,

                    ChildID = c.ChildID,

                    ParentName = p.Name,

                    ChildName = c.ChildName

                }).ToList();

            joinedList.ForEach(c => Console.WriteLine(c.ToString()));

        }

澳门葡京备用网址 118)

  运行结果如下图所示:

澳门葡京备用网址 119

1.伍 分组老师GroupBy方法

  在数据库中,大家要对查询结果进行分组会用到
group by
语句,在行业内部查询运算符中,大家也有相应的GroupBy方法。那里,如若大家对Person数据集依照性别进行归类,该怎么来写代码呢?

澳门葡京备用网址 120)

                    static
                            void SQOGroupByDemo()

        {

            List<Person> personList = GetPersonList();

 

            IEnumerable<IGrouping<bool, Person>> groups =

                personList.GroupBy(p => p.Gender);

            IList<IGrouping<bool, Person>> groupList = groups.ToList();

 

                    foreach (IGrouping<bool, Person> group in groupList)

            {

                Console.WriteLine("Group:{0}", group.Key ? "男" : "女");

                    foreach (Person p in group)

                {

                    Console.WriteLine(p.ToString());

                }

            }

        }

澳门葡京备用网址 121)

  (一)那里供给专注的是:通过GroupBy方法后回到的是2个IEnumerable<IGrouping<TKey,
TSource>>
花色,个中TKey是分组遵照的连串,这里是依照Gender来分组的,而Gender又是bool类型,所以TKey那里为bool类型。TSource则是分组之后依次要素的品类,那里是将List<Person>集合进行分组,因而分完组后各样成分都存款和储蓄的是Person类型,所以TSource这里为Person类型,Do
you understand now?

  (贰)运维结果如下图所示:

澳门葡京备用网址 122

  (三)恐怕有人会说小编咋记得住GroupBy再次来到的卓殊类型,太长了,我也不想记。如何是好呢?不怕,大家得以采用var关键字嘛:

澳门葡京备用网址 123)

                    var annoyGroups = personList.GroupBy(p => p.Name).ToList();

                    foreach (var group in annoyGroups)

            {

                Console.WriteLine("Group:{0}", group.Key);

                    foreach (var p in group)

                {

                    Console.WriteLine(p.ToString());

                }

            }

澳门葡京备用网址 124)

1.陆 分页实战Skip与Take方法

  相信广大人都利用过科班查询运算符进行分页操作,这里大家再次来看望怎样借助Skip与Take方法来兑现分页操作。照旧以PersonList集合为例,假设页面上的报表每页显示五条数据,该怎么来写代码呢?

澳门葡京备用网址 125)

                    static
                            void SQOPagedDemo()

        {

                        // 这里假设每页5行数据


            // 第一页


            Console.WriteLine("First Page:");

                    var firstPageData = GetPagedListByIndex(1, 5);

            firstPageData.ForEach(d => Console.WriteLine(d.ToString()));

                        // 第二页


            Console.WriteLine("Second Page:");

                    var secondPageData = GetPagedListByIndex(2, 5);

            secondPageData.ForEach(d => Console.WriteLine(d.ToString()));

                        // 第三页


            Console.WriteLine("Third Page:");

                    var thirdPageData = GetPagedListByIndex(3, 5);

            thirdPageData.ForEach(d => Console.WriteLine(d.ToString()));

        }

 

                    static List<Person> GetPagedListByIndex(int pageIndex, int pageSize)

        {

            List<Person> dataList = GetMorePersonList();

                    return dataList.Skip((pageIndex - 1) * pageSize)

                .Take(pageSize).ToList();

        }

澳门葡京备用网址 126)

  运营结果如下图所示:

澳门葡京备用网址 127

壹.七 浅谈延迟加载与当下加载

  (1)延迟加载(Lazy
Loading):
除非在我们亟需多少的时候才去数据库读取加载它。

  在正规查询运算符中,Where方法正是2个满腹珠玑的延迟加载案例。在实质上的开发中,大家反复会使用部分O普拉多M框架例如EF去操作数据库,Where方法的应用则是历次调用都只是在此起彼伏生成SQL语句时扩充三个询问条件,EF不能明确本次查询是还是不是已经增加停止,所以并未有主意木有办法在种种Where方法执行的时候分明最终的SQL语句,只好回到四个DbQuery对象,当使用到这些DbQuery对象的时候,才会依据全体规则转移最后的SQL语句去查询数据库。

    var searchResult = personList.Where(p =>

          p.Gender == false).Where(p => p.Age > 20)

          .Where(p=>p.Name.Contains("奶茶"));

  (2)立马加载(Eager
Loading):
加载数据时就把该对象相关联的别的表的数量二只加载到内部存款和储蓄器对象中去。

  在正规查询运算符中,FindAll方法就是贰个超人的即时加载案例。与延迟加载相呼应,在支付中如果选拔FindAll方法,EF会依据办法中的条件自动生成SQL语句,然后随即与数据库举行互动获取查询结果,并加载到内部存款和储蓄器中去。

                    var searchResult = personList.FindAll(p=>p.Gender == false


                && p.Name.Contains("奶茶"));

二、查询艺术哪个人更加快?LINQ:[ C# 三.0/.NET 3.x 新增特色 ]

2.一 初识LINQ:类似SQL风格的代码

  LINQ又称言语集成查询,它是C#
三.0的新语法。在更多的人看来,它是1种有益的询问表明式,可能说是和SQL风格周围的代码

                    var maleList = from p in personList

                    where p.Gender == true


                        select p;

  (1)LINQ表明式以”from”初始,以”select
或 group by子句”结尾;

  (2)LINQ说明式的出口是三个IEnumerable<T> 或 IQueryable<T> 集合;(注:T 的门类 由
select 或 group by 推测出来)

二.二 LINQ使用:完毕除Skip和Take外的正儿8经查询运算符的效应

  (1)基本尺度查询:

澳门葡京备用网址 128

澳门葡京备用网址 129)

            List<Person> personList = GetPersonList();

            List<Children> childList = GetChildrenList();

                        // 基本条件查询


            Console.WriteLine("Basic Query:");

                    var maleList = from p in personList

                    where p.Gender == true


                    select p;

            maleList.ToList().ForEach(m =>

                Console.WriteLine(m.ToString()));

澳门葡京备用网址 130)

  (二)排序条件查询:

澳门葡京备用网址 131

澳门葡京备用网址 132)

                        // 排序条件查询


            Console.WriteLine("Order Query:");

                    var orderedList = from p in personList

                    orderby p.Age descending

                    orderby p.Name ascending

                    select p;

            orderedList.ToList().ForEach(m =>

                Console.WriteLine(m.ToString()));

澳门葡京备用网址 133)

  (3)连接查询:

澳门葡京备用网址 134

澳门葡京备用网址 135)

                        // Join连接查询


            Console.WriteLine("Join Query:");

                    var joinedList = from p in personList

                             join c in childList

                             on p.ID equals c.ParentID

                    select
                            new


                             {

                                 Person = p,

                                 Child = c

                             };

                    foreach (var item in joinedList)

            {

                Console.WriteLine(item.ToString());

            }

澳门葡京备用网址 136)

  (④)分组查询:

澳门葡京备用网址 137

澳门葡京备用网址 138)

                        // 分组条件查询


            Console.WriteLine("Group Query:");

                    var groupList = from p in personList

                            group p by p.Gender;

                    foreach (var group in groupList)

            {

                Console.WriteLine("Group:{0}", 

                    group.Key? "男":"女");

                    foreach(var item in group)

                {

                    Console.WriteLine(item.ToString());

                }

            }

澳门葡京备用网址 139)

  运营结果请参考上1节标准查询运算符中相关的运维结果,或下载附属类小部件运营查看,那里不再贴图。

二.三 LINQ本质:生成对应的行业内部查询运算符

  作为多个精心的.Net码农,大家不禁对LINQ表明式为大家做了如何工作而奇怪?于是,大家又想起了我们的”滑高筒靴”—Reflector或ILSpy,去看望编写翻译器为大家做了怎么着事!

  (一)以上述的骨干尺度查询代码为例,大家来看原来编写翻译器将LINQ生成了相应的正统查询运算符,即Where扩张方法:

澳门葡京备用网址 140

  (2)再来看看排序条件查询的代码,也是生成了相应的正规化查询运算符,即OrderBy扩张方法:

澳门葡京备用网址 141

  (3)总结:LINQ编译后会生成对应的科班查询运算符(查询->Where,排序->OrderBy,连接->Join,分组->GroupBy),所以LINQ表明式其实就是看似于SQL风格的壹种尤为和谐语法糖而已。其本质照旧增加方法、泛型委托等”旧酒”,被二个”新瓶子”所包装了四起,就变得巨大上了。

名目繁多总计

  须臾,4篇作品的介绍就到此甘休了,其实本种类介绍的都以不算新语法,其实也足以说成是老语法了。说它们新,只可是是周旋于.NET老版本而言,而且平时支付中山大学家有望未有注意到的一些细节,本种类做了2个简易的牵线。这几天看到不可胜数田园里的童鞋初叶关切C#
6.0的新特性了,粗略看了看,语法糖居多,相信经过了那一各类的探秘,对于新的语法糖,大家得以站在二个相比较高的万丈去看待它们。最终,感激各位园友的浏览,以及给小编的一对鼓励,再一次谢谢!

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website