为什么Func而不是谓词?

时间:2021-08-26 22:01:47

This is just a curiosity question I was wondering if anyone had a good answer to:

这只是一个好奇的问题,我想知道是否有人有一个好的答案:

In the .NET Framework Class Library we have for example these two methods:

在。net Framework类库中,我们有两种方法:

public static IQueryable<TSource> Where<TSource>(
    this IQueryable<TSource> source,
    Expression<Func<TSource, bool>> predicate
)

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

Why do they use Func<TSource, bool> instead of Predicate<TSource>? Seems like the Predicate<TSource> is only used by List<T> and Array<T>, while Func<TSource, bool> is used by pretty much all Queryable and Enumerable methods and extension methods... what's up with that?

为什么他们使用Func 而不是谓词 ?似乎谓词 只用于List 和Array ,而Func 被几乎所有可查询和可枚举的方法和扩展方法所使用……那是什么? ,> ,>

4 个解决方案

#1


156  

While Predicate has been introduced at the same time that List<T> and Array<T>, in .net 2.0, the different Func and Action variants come from .net 3.5.

虽然在.net 2.0中,谓词同时列出了 和Array ,但是不同的Func和Action变体来自。net 3.5。

So those Func predicates are used mainly for consistency in the LINQ operators. As of .net 3.5, about using Func<T> and Action<T> the guideline states:

所以这些Func谓词主要用于LINQ操作符的一致性。在。net 3.5中,关于使用Func 和Action 指南说明如下:

Do use the new LINQ types Func<> and Expression<> instead of custom delegates and predicates

是否使用新的LINQ类型Func<>和表达式<>代替自定义委托和谓词

#2


106  

I've wondered this before. I like the Predicate<T> delegate - it's nice and descriptive. However, you need to consider the overloads of Where:

我想知道这个。我喜欢谓词 委托-它很好而且具有描述性。但是,您需要考虑的是:

Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

That allows you to filter based on the index of the entry as well. That's nice and consistent, whereas:

这也允许您根据条目的索引进行筛选。这很好也很一致,但是

Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

wouldn't be.

不会。

#3


29  

Surely the actual reason for using Func instead of a specific delegate is that C# treats separately declared delegates as totally different types.

使用Func而不是特定委托的真正原因是c#将单独声明的委托视为完全不同的类型。

Even though Func<int, bool> and Predicate<int> both have identical argument and return types, they are not assignment-compatible. So if every library declared its own delegate type for each delegate pattern, those libraries would not be able to interoperate unless the user inserts "bridging" delegates to perform conversions.

虽然Func 和谓词 都具有相同的参数和返回类型,但它们并不与赋值兼容。因此,如果每个库都为每个委托模式声明了自己的委托类型,那么这些库将无法互操作,除非用户插入“桥接”委托来执行转换。 、bool>

    // declare two delegate types, completely identical but different names:
    public delegate void ExceptionHandler1(Exception x);
    public delegate void ExceptionHandler2(Exception x);

    // a method that is compatible with either of them:
    public static void MyExceptionHandler(Exception x)
    {
        Console.WriteLine(x.Message);
    }

    static void Main(string[] args)
    {
        // can assign any method having the right pattern
        ExceptionHandler1 x1 = MyExceptionHandler; 

        // and yet cannot assign a delegate with identical declaration!
        ExceptionHandler2 x2 = x1; // error at compile time
    }

By encouraging everyone to use Func, Microsoft is hoping that this will alleviate the problem of incompatible delegate types. Everyone's delegates will play nicely together, because they will just be matched up based on their parameter/return types.

通过鼓励每个人使用Func,微软希望这将缓解不兼容委托类型的问题。每个委托都可以很好地结合在一起,因为它们只是根据它们的参数/返回类型进行匹配。

It doesn't solve all problems, because Func (and Action) can't have out or ref parameters, but those are less commonly used.

它并不能解决所有问题,因为Func(和操作)不可能有或引用参数,但是这些参数很少被使用。

Update: in the comments Svish says:

更新:在评论中Svish说:

Still, switching a parameter type from Func to Predicate and back, doesn't seem to make any difference? At least it still compiles without any problems.

不过,将参数类型从Func切换到谓词和返回,似乎没有什么区别?至少它在编译时没有任何问题。

Yes, as long as your program only assigns methods to delegates, as in the first line of my Main function. The compiler silently generates code to new a delegate object that forwards on to the method. So in my Main function, I could change x1 to be of type ExceptionHandler2 without causing a problem.

是的,只要您的程序只向委托分配方法,就像我的主函数的第一行。编译器无声地生成代码,以创建一个委托对象,并将其转发给该方法。所以在我的主要函数中,我可以把x1改变为类型异常,而不引起问题。

However, on the second line I try to assign the first delegate to another delegate. Even thought that 2nd delegate type has exactly the same parameter and return types, the compiler gives error CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'.

但是,在第二行,我尝试将第一个委托分配给另一个委托。即使第二委托类型具有完全相同的参数和返回类型,编译器也会给出错误CS0029:不能隐式地将类型'ExceptionHandler1'转换为'ExceptionHandler2'。

Maybe this will make it clearer:

也许这将使它更清晰:

public static bool IsNegative(int x)
{
    return x < 0;
}

static void Main(string[] args)
{
    Predicate<int> p = IsNegative;
    Func<int, bool> f = IsNegative;

    p = f; // Not allowed
}

My method IsNegative is a perfectly good thing to assign to the p and f variables, as long as I do so directly. But then I can't assign one of those variables to the other.

我的方法是负的,对于p和f变量赋值是很好的,只要我直接这么做。但是我不能把其中一个变量赋给另一个。

#4


26  

The advice (in 3.5 and above) is to use the Action<...> and Func<...> - for the "why?" - one advantage is that "Predicate<T>" is only meaningful if you know what "predicate" means - otherwise you need to look at object-browser (etc) to find the signatute.

建议(在3.5及以上)是使用行动<…>和Func <…> -为什么?-一个优点是“谓词 ”只有当您知道“谓词”的含义时才有意义——否则您需要查看object-browser(等)来查找签名。

Conversely Func<T,bool> follows a standard pattern; I can immediately tell that this is a function that takes a T and returns a bool - don't need to understand any terminology - just apply my truth test.

反之Func 遵循标准模式;我可以马上看出这是一个函数,它接受T并返回bool——不需要理解任何术语——只需应用我的真值测试。 ,bool>

For "predicate" this might have been OK, but I appreciate the attempt to standardise. It also allows a lot of parity with the related methods in that area.

对于“谓词”,这可能是可以的,但是我很欣赏标准化的尝试。它还允许与该领域的相关方法进行大量的奇偶性。

#1


156  

While Predicate has been introduced at the same time that List<T> and Array<T>, in .net 2.0, the different Func and Action variants come from .net 3.5.

虽然在.net 2.0中,谓词同时列出了 和Array ,但是不同的Func和Action变体来自。net 3.5。

So those Func predicates are used mainly for consistency in the LINQ operators. As of .net 3.5, about using Func<T> and Action<T> the guideline states:

所以这些Func谓词主要用于LINQ操作符的一致性。在。net 3.5中,关于使用Func 和Action 指南说明如下:

Do use the new LINQ types Func<> and Expression<> instead of custom delegates and predicates

是否使用新的LINQ类型Func<>和表达式<>代替自定义委托和谓词

#2


106  

I've wondered this before. I like the Predicate<T> delegate - it's nice and descriptive. However, you need to consider the overloads of Where:

我想知道这个。我喜欢谓词 委托-它很好而且具有描述性。但是,您需要考虑的是:

Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

That allows you to filter based on the index of the entry as well. That's nice and consistent, whereas:

这也允许您根据条目的索引进行筛选。这很好也很一致,但是

Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

wouldn't be.

不会。

#3


29  

Surely the actual reason for using Func instead of a specific delegate is that C# treats separately declared delegates as totally different types.

使用Func而不是特定委托的真正原因是c#将单独声明的委托视为完全不同的类型。

Even though Func<int, bool> and Predicate<int> both have identical argument and return types, they are not assignment-compatible. So if every library declared its own delegate type for each delegate pattern, those libraries would not be able to interoperate unless the user inserts "bridging" delegates to perform conversions.

虽然Func 和谓词 都具有相同的参数和返回类型,但它们并不与赋值兼容。因此,如果每个库都为每个委托模式声明了自己的委托类型,那么这些库将无法互操作,除非用户插入“桥接”委托来执行转换。 、bool>

    // declare two delegate types, completely identical but different names:
    public delegate void ExceptionHandler1(Exception x);
    public delegate void ExceptionHandler2(Exception x);

    // a method that is compatible with either of them:
    public static void MyExceptionHandler(Exception x)
    {
        Console.WriteLine(x.Message);
    }

    static void Main(string[] args)
    {
        // can assign any method having the right pattern
        ExceptionHandler1 x1 = MyExceptionHandler; 

        // and yet cannot assign a delegate with identical declaration!
        ExceptionHandler2 x2 = x1; // error at compile time
    }

By encouraging everyone to use Func, Microsoft is hoping that this will alleviate the problem of incompatible delegate types. Everyone's delegates will play nicely together, because they will just be matched up based on their parameter/return types.

通过鼓励每个人使用Func,微软希望这将缓解不兼容委托类型的问题。每个委托都可以很好地结合在一起,因为它们只是根据它们的参数/返回类型进行匹配。

It doesn't solve all problems, because Func (and Action) can't have out or ref parameters, but those are less commonly used.

它并不能解决所有问题,因为Func(和操作)不可能有或引用参数,但是这些参数很少被使用。

Update: in the comments Svish says:

更新:在评论中Svish说:

Still, switching a parameter type from Func to Predicate and back, doesn't seem to make any difference? At least it still compiles without any problems.

不过,将参数类型从Func切换到谓词和返回,似乎没有什么区别?至少它在编译时没有任何问题。

Yes, as long as your program only assigns methods to delegates, as in the first line of my Main function. The compiler silently generates code to new a delegate object that forwards on to the method. So in my Main function, I could change x1 to be of type ExceptionHandler2 without causing a problem.

是的,只要您的程序只向委托分配方法,就像我的主函数的第一行。编译器无声地生成代码,以创建一个委托对象,并将其转发给该方法。所以在我的主要函数中,我可以把x1改变为类型异常,而不引起问题。

However, on the second line I try to assign the first delegate to another delegate. Even thought that 2nd delegate type has exactly the same parameter and return types, the compiler gives error CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'.

但是,在第二行,我尝试将第一个委托分配给另一个委托。即使第二委托类型具有完全相同的参数和返回类型,编译器也会给出错误CS0029:不能隐式地将类型'ExceptionHandler1'转换为'ExceptionHandler2'。

Maybe this will make it clearer:

也许这将使它更清晰:

public static bool IsNegative(int x)
{
    return x < 0;
}

static void Main(string[] args)
{
    Predicate<int> p = IsNegative;
    Func<int, bool> f = IsNegative;

    p = f; // Not allowed
}

My method IsNegative is a perfectly good thing to assign to the p and f variables, as long as I do so directly. But then I can't assign one of those variables to the other.

我的方法是负的,对于p和f变量赋值是很好的,只要我直接这么做。但是我不能把其中一个变量赋给另一个。

#4


26  

The advice (in 3.5 and above) is to use the Action<...> and Func<...> - for the "why?" - one advantage is that "Predicate<T>" is only meaningful if you know what "predicate" means - otherwise you need to look at object-browser (etc) to find the signatute.

建议(在3.5及以上)是使用行动<…>和Func <…> -为什么?-一个优点是“谓词 ”只有当您知道“谓词”的含义时才有意义——否则您需要查看object-browser(等)来查找签名。

Conversely Func<T,bool> follows a standard pattern; I can immediately tell that this is a function that takes a T and returns a bool - don't need to understand any terminology - just apply my truth test.

反之Func 遵循标准模式;我可以马上看出这是一个函数,它接受T并返回bool——不需要理解任何术语——只需应用我的真值测试。 ,bool>

For "predicate" this might have been OK, but I appreciate the attempt to standardise. It also allows a lot of parity with the related methods in that area.

对于“谓词”,这可能是可以的,但是我很欣赏标准化的尝试。它还允许与该领域的相关方法进行大量的奇偶性。