首页 > 代码库 > C# Func<>委托

C# Func<>委托

以前我们为了能够调用一个方法,必须比照这个方法定义一个相应的delegate.

原先我们定义delegate

// 委托声明 -- 定义一个签名:
delegate doubleMathAction(double num);
class DelegateTest
{
    // 符合委托声明的常规方法
    static double Double(double input)
    {
        return input * 2;
    }
 
    static void Main()
    {
     原版:   // 使用一个命名方法实例化委托类型
        MathAction ma = Double;
 
        // 调用委托实例
        double multByTwo = ma(4.5);
        Console.WriteLine(multByTwo);
 
    简化版1:   // 再用匿名方法来实例化委托类型
        MathAction ma2 = delegate(double input)
        {
            return input * input;
        };
 
        double square = ma2(5);
        Console.WriteLine(square);
 
     简化版2:  // 最后用Lambda表达式来实例化委托类型
        MathAction ma3 = s => s * s * s;
        double cube = ma3(4.375);
 
        Console.WriteLine(cube);
    }
}

这个是否能有更好的实现办法呢?

答案是:肯定有了.也就是有通用的delegate了。在.NETFramework 3.5中,提供了两类通用的delegate

如果方法有返回值,则使用Func,或者Func<>

如果方法没有返回值,则使用Action,或者Action<>

Func<T,TR>

T

此委托封装的方法的参数类型。

TR

此委托封装的方法的返回值类型。

 

在使用 Func<T,TResult>委托时,不必显式定义一个封装只有一个参数的方法的委托。以下示例简化了此代码,它所用的方法是实例化 Func<T, TResult>委托,而不是显式定义一个新委托并将命名方法分配给该委托。


使Func<>委托,我们这样写

using System;

public classLambdaExpression
{
   public static void Main()
   { 
      Func<string, string> convert = s=> s.ToUpper();//该方法将小写字母转为大写
      string name = "Dakota";
      Console.WriteLine(convert(name));  
   }
}

Func委托是system下的全局函数,不用我们自定,系统自定义的,供我们使用,带有多个重载.

这里我们除了使用Func委托外,还是用了Labdab表达式.这里我再谈谈这个表达式.

Lambda表达式的基础类型是泛型 Func委托之一。 这样能以参数形式传递 lambda表达式,而不用显式将其分配给委托。 尤其是,因为 System.Linq命名空间中许多类型方法具有Func<T, TResult>参数,因此可以给这些方法传递 lambda表达式,而不用显式实例化 Func<T, TResult>委托。

下面一行代码将生成一个序列,其中包含 numbers 数组中在 9左侧的所有元素,因为它是序列中第一个不满足条件的数字:

int[] n= { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);

实例2

var firstSmallNumbers =numbers.TakeWhile((n, index) => n >= index);

此示例展示了如何通过将输入参数括在括号中来指定多个输入参数。该方法将返回数字数组中的所有元素,直至遇到一个值小于其位置的数字为止。不要将 lambda运算符 (=>)与大于等于运算符 (>=)混淆。

 

三种委托写法对比

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace func
{
//委托声明 -- 定义一个签名:
delegate double MathAction(double num);
public class Program
{
// 符合委托声明的常规方法
static double Double(double input)
{
return input * 2;
}
 
static void Main(string[] args)
{
// 使用一个命名方法实例化委托类型
/*
 * 写法一,需要写出专门委托的函数,还需要自定义委托
 **/
MathAction ma = Double;//注意这里千万不可有Double(),否则就成了一个返回类型,是报错的,这里是制定函数的地址,给定的是函数的地址
 
//调用委托
double result1 = ma(4.5);
 
//使用系统自定义委托实例化委托类型
/*
 * 写法二,需要写出专门委托的函数,不需要自定义委托,使用系统委托
 **/
Func<double,double> func = Double;
 
//调用委托
double result2 = func(4.5);
 
//系统委托使用lamdba进行传递参数
/*
 * 写法三,不需要写出专门委托的函数,还需要自定义委托
 **/
Func<double, double> result = s=> s * 2;//写法还可以换成lamdba语句块,适应多个参数的写法
 
double result3=result(4.5);
 
Func<double,double> result4 = s =>
{
return s * 2;
};
 
Console.WriteLine(result1);
Console.WriteLine(result3);
Console.WriteLine(result2);
Console.WriteLine(result4(4.5));
} 
}
 
}


效果图


 

同样的输出效果,但是编写代码的效果确实不同的。代码的质量也是不同的。当然了也是要对自己的问题进行负责的。lamdba的使用简化的代码,但是如果自己不是对这个很熟悉,很容易造成出现问题,如从着手错误的源泉。匿名函数的写法解决的这个问题。但是匿名函数却没有Lamdba简便。这就是折中方法吧。看自己更喜欢哪种了。

 

小结:

Func的委托中,我们可以看出,它简化了我们自己定义委托带来的繁琐,同时它更好的结合了Lamdba的使用。减少了自定义函数的作用。同时也是有缺点的,就是错误的出现不容易发现是那里。Action委托的使用与Func雷同,这里就不在说了。希望自己的总结可以对大家有所帮助。