zoukankan      html  css  js  c++  java
  • .NET中的泛型委托

    .Net中有一个内置的委托 Func

    它总共有以下5种形式

    1.  Func<TResult>

    2.  Func<T,TResult>

    3.  Func<T1,T2,TResult>

    4.  Func<T1,T2,T3,TResult>

    5.  Func<T1,T2,T3,T4,TResult>

    上面5种形式,第1种 Func<TResult> 没有参数,只有返回值

    我们来看一个例子

    private delegate string MyDelegate();
    
    public static string OutputDelegate()
    {
         return "Test delegate";
    }
    
    public static void Main(string[] args)
    {
              MyDelegate testFunc = OutputDelegate;
       
              Console.WriteLine(testFunc());  // 输出 Test delegate
         
    }

    在这个例子中,我们自己定义了一个委托MyDelegate. 但是 上面我们也说了,.Net中有自己内置的委托,或者说是.Net中默认自带的委托, 我们来看看如何使用.Net自带的委托 Func<TResult>

    public static string OutputDelegate()
    {
         return "Test delegate";
    }
    
    public static void Main(string[] args)
    {
              Func<string> testFunc = OutputDelegate;
       
              Console.WriteLine(testFunc());  // 输出 Test delegate
         
    }

    在上面,我们使用了.net自带的委托的第一种类型Func<TResult>, 这个委托没有参数传入,返回值类型为TResult. 由于上面OutputDelegate方法中返回string类型,所以对应委托就是Func<string>

    如果有参数呢,我们就需要使用其他4种形式了。 我们来看一看第2种形式委托Func<T,TResult>的使用

    public static string OutputDelegate(string testStr)
    {
         return testStr + testStr;
    }
    
    public static void Main(string[] args)
    {
              Func<string,string> testFunc = OutputDelegate;
    
              string strResult = testFunc("test");
       
              Console.WriteLine(strResult);  // 输出 test test
         
    }

     上面的.Net内置委托Func也支持Lambda的形式调用, 我们来看一个例子

    Func<string,string> myDelegate = x => x + x;
    
    Console.WriteLine(myDelegate("test")); // 输出 testtest

    我们现在属性了这个内置委托Func,那么它一般在哪里使用呢,或者说在什么场景下使用比较多呢

    事实上,在编程过程中,它使用最多的场景是作为函数的参数,比如下面这样

    string GetResult(Func<string,string>)

    在这个方法中,参数是一个代理,我们通常会通过传入一个Lambda表达式,这个代理输入参数是string类型,而返回值也是string类型,所以你看GetResult函数的返回类型就是string类型

     我们知道,Linq查询操作中有一些聚合函数(count,max,min,sum,average,aggregate,longcount),我们来看看其中count的原型

    public static int Count<TSource>(this IEnumerable<TSource> source);
    public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource,bool> predicate);

    我们从上面看到,Linq中的Count聚合函数有两个原型,第一个就是单独的计算序列中的元素的数量总和。  而第2个原型有一个委托函数,用来筛选满足一定条件的元素,然后再计算满足条件的数量和. 我们来看个实现它们的例子

    private void GetCount()
    {
         int[] intList = new int[] {1,2,3,3,4,8,9};
    
        var countResult = intList.Count() //输出 7
        var countResult2 = intList.Count(x=>x > 4) //输出 2
    
    
    
    }

    我们再来看看其中的sum函数的一个原型

    public static int Sum<TSource>(this IEnumerable<TSource> source, Func<TSource,int> selector);

     看完这些,有没有啥感觉,有没有发现自己也可以写一个Linq的聚合函数,使用类似它默认自带的聚合函数同样的方法,使用扩展方法,委托作为参数,我们自己来试试, 取名为MyLinqFunc

    public static TSource MyLinqFunc(this IEnumerable<TSource> source, Func<TSource, bool> funcCondition)
    {
         foreach(TSource item in source)
         {
                
                   if(funcCondition(item))
                   {
                        return (item);
                   }
                 
         }
         
         throw new Exception("没有满足条件的元素");
    
    }

    现在我们来写一个例子,可以使用这个自己定义的Linq的聚合函数

    class myClass
    {
          static void Main(string[] args)
          {
                List<int> intList = new List<int>(){5,6,8,9,4,3,2,1};
                int result = intList.MyLinqFunc(t=>t < 2);  //输出 1  这里使用上面我们自己定义的Linq聚合函数 MyLinqFunc
                Console.WriteLine(result); 
    
    
           }
    
    
    }

     看了上面的分析后,我们再去看msdn上关于Enumerable.Select<TSource,TResult>方法,就更容易理解,可以自己去看https://msdn.microsoft.com/zh-cn/library/bb548891(v=vs.110).aspx   https://msdn.microsoft.com/zh-cn/library/bb534869(v=vs.110).aspx

    上面我们讨论了.Net中的泛型委托,我们知道,还有一个概念,就是委托表达式,这样一种形式Expression<Func<TSource,TResult>>. 那么这两者到底有什么区别呢。这是一个很容易让人摸不清头脑的问题

    我们来看看

    Func<TSource,TResult> 是委托

    Expression<Func<TSource,TResult>>是表达式

    Expression要编译后(调用Expression的Compile方法)才能变成delegate, 才能运行。 举个例子如下

    Expression<Func<int,bool>> ex = x => x > 10;
    Func<int,bool> myFunc = ex.Compile();

    现在我们就可以调用myFunc:

    myFunc(5)  //返回false

    myFunc(12) //返回true

    而表达式是不可以直接调用的

     但是在Linq to Entity的Where查询条件中,就应该使用Expression,而不是使用委托。 比如如下是错误的

    Func<tbUser,bool> existFunc = u => u.userID == id && u.userName == name;
    
    _tbUserRepository.Entities.Where(existFunc);

    上面这里,where里面的参数是一个委托,这个是错误的。实际上,where里面需要的参数是Expression, 所以正确的方式应该如下

    Expression<Func<tbUser,bool>> existFunc = u => u.userID == id && u.userName == name;
    
    _tbUserRepository.Entities.Where(existFunc);
  • 相关阅读:
    保护模式下通过写显存在屏幕上输出字符串
    Linux0.01 引导代码分析-head.s
    OpenGL Super Bible 第四章 Transform 程序绘图部分代码解析
    Ubuntu10.04 下编译 OpenOffice DEV300 分支
    今天把博客开通了,欢迎来访!
    沟通的工具ER图
    为什么博客叫秋水?
    mysql.基础笔记
    如何阅读别人的C代码
    Github搜索与查看
  • 原文地址:https://www.cnblogs.com/wphl-27/p/9442281.html
Copyright © 2011-2022 走看看