为什么`Predicate `与`Func `不匹配?

时间:2022-11-02 21:58:21

I try to compile the following code in C#:

我尝试在C#中编译以下代码:

public static T FirstEffective(IEnumerable<T> list) 
{
    Predicate<T> pred = x => x != null;
    return Enumerable.FirstOrDefault(list, pred);
}

The compiler (Mono/.NET 4.0) gives the following error:

编译器(Mono / .NET 4.0)给出以下错误:

File.cs(139,47) The best overloaded method match for `System.Linq.Enumerable.FirstOrDefault<T>(this System.Collections.Generic.IEnumerable<T>,System.Func<T,bool>)' has some invalid arguments
/usr/lib/mono/4.0/System.Core.dll (Location of the symbol related to previous error)
File.cs(139,47): error CS1503: Argument `#2' cannot convert `System.Predicate<T>' expression to type `System.Func<T,bool>'

This is rather strange since a Predicate<T> is in fact a function that takes as input a parameter T and returns a bool (T is even "covariant" thus a specialization of T is allowed). Do delegates do not take the "Liskov Substitution principle" into account to derive that Predicate<T> is equivalent to Func<T,bool>? As far as I know this equivalence problem should be decidable.

这是相当奇怪的,因为Predicate 实际上是一个函数,它将参数T作为输入并返回一个bool(T甚至是“协变”,因此允许T的特化)。代表们是否不考虑“Liskov替换原则”来推导出Predicate 相当于Func ?据我所知,这个等价问题应该是可判定的。 ,bool>

3 个解决方案

#1


15  

C# specification is clear about that:

C#规范很清楚:

15.1 Delegate declarations

15.1代表声明

Delegate types in C# are name equivalent, not structurally equivalent. Specifically, two different delegate types that have the same parameter lists and return type are considered different delegate types.

C#中的委托类型是名称等价的,在结构上不等同。具体而言,具有相同参数列表和返回类型的两种不同委托类型被视为不同的委托类型。

That's why your code doesn't compile.

这就是你的代码无法编译的原因。

You can make it work by calling the delegate, instead of passing it:

您可以通过调用委托来使其工作,而不是传递它:

public static T FirstEffective (IEnumerable<T> list) {
    Predicate<T> pred = x => x != null;
    return Enumerable.FirstOrDefault (list, x => pred(x));
}

Update

更新

There is a great blog post by Eric Lippert: former member of C# Team as Microsoft, which answers your question in much details: Delegates and structural identity.

Eric Lippert撰写了一篇很棒的博客文章:C#Team的前成员,微软,它详细回答了你的问题:代表和结构身份。

#2


4  

Delegate types are not implicitly convertible, even when they have all the same parameter and return information. There is an easy workaround for your case though. You can use the .Invoke method on your delegate instance.

委托类型不可隐式转换,即使它们具有所有相同的参数和返回信息。但是,您的案例有一个简单的解决方法。您可以在委托实例上使用.Invoke方法。

public static T FirstEffective<T>(IEnumerable<T> list)
{
    Predicate<T> pred = x => x != null;
    return Enumerable.FirstOrDefault(list, pred.Invoke);
}

As to the question of why delegates work this way, the answer is that it was a design decision. Classes that have identical public interfaces aren't implicitly convertible either, so it's not really inconsistent.

至于为什么代表们以这种方式工作的问题,答案是这是一个设计决策。具有相同公共接口的类也不可隐式转换,因此它并不真正不一致。

#3


1  

Quite belated but coincidentally I stumbled up on the same question and the accurate answer can be found here: important comment

相当姗姗来迟,但巧合的是我偶然发现了同样的问题,可以在这里找到准确的答案:重要评论

Basically it means that it's an inconsistency based on an unfortunate decision to implement it this way. Whilst predicate<T> == func<T, bool>, they are different types despite the same signature. I suppose for reasons of backward compatibility one can convert an expression and/or lambda and then return a predicate through new predicate<T>(func<T, bool>).

基本上它意味着它是基于不幸的决定以这种方式实现它的不一致。虽然谓词 == func ,但它们是不同的类型,尽管签名相同。我认为出于向后兼容性的原因,可以转换表达式和/或lambda,然后通过新谓词 (func )返回谓词。 ,bool> ,bool>

#1


15  

C# specification is clear about that:

C#规范很清楚:

15.1 Delegate declarations

15.1代表声明

Delegate types in C# are name equivalent, not structurally equivalent. Specifically, two different delegate types that have the same parameter lists and return type are considered different delegate types.

C#中的委托类型是名称等价的,在结构上不等同。具体而言,具有相同参数列表和返回类型的两种不同委托类型被视为不同的委托类型。

That's why your code doesn't compile.

这就是你的代码无法编译的原因。

You can make it work by calling the delegate, instead of passing it:

您可以通过调用委托来使其工作,而不是传递它:

public static T FirstEffective (IEnumerable<T> list) {
    Predicate<T> pred = x => x != null;
    return Enumerable.FirstOrDefault (list, x => pred(x));
}

Update

更新

There is a great blog post by Eric Lippert: former member of C# Team as Microsoft, which answers your question in much details: Delegates and structural identity.

Eric Lippert撰写了一篇很棒的博客文章:C#Team的前成员,微软,它详细回答了你的问题:代表和结构身份。

#2


4  

Delegate types are not implicitly convertible, even when they have all the same parameter and return information. There is an easy workaround for your case though. You can use the .Invoke method on your delegate instance.

委托类型不可隐式转换,即使它们具有所有相同的参数和返回信息。但是,您的案例有一个简单的解决方法。您可以在委托实例上使用.Invoke方法。

public static T FirstEffective<T>(IEnumerable<T> list)
{
    Predicate<T> pred = x => x != null;
    return Enumerable.FirstOrDefault(list, pred.Invoke);
}

As to the question of why delegates work this way, the answer is that it was a design decision. Classes that have identical public interfaces aren't implicitly convertible either, so it's not really inconsistent.

至于为什么代表们以这种方式工作的问题,答案是这是一个设计决策。具有相同公共接口的类也不可隐式转换,因此它并不真正不一致。

#3


1  

Quite belated but coincidentally I stumbled up on the same question and the accurate answer can be found here: important comment

相当姗姗来迟,但巧合的是我偶然发现了同样的问题,可以在这里找到准确的答案:重要评论

Basically it means that it's an inconsistency based on an unfortunate decision to implement it this way. Whilst predicate<T> == func<T, bool>, they are different types despite the same signature. I suppose for reasons of backward compatibility one can convert an expression and/or lambda and then return a predicate through new predicate<T>(func<T, bool>).

基本上它意味着它是基于不幸的决定以这种方式实现它的不一致。虽然谓词 == func ,但它们是不同的类型,尽管签名相同。我认为出于向后兼容性的原因,可以转换表达式和/或lambda,然后通过新谓词 (func )返回谓词。 ,bool> ,bool>