我有一些代码。这不是真正的代码,但与我在生产中的问题非常相似。 第 2 点中未编译的ASupplier
调用var filtered
导致List<IA>
。它看起来像是有效原因Where
声明为
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
但我不明白为什么第 3 点有效,因为 FixedIACondition 声明与调用的结果相似IAConditionCreator
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqWhereConditionProblem
{
internal class Program
{
public static void Main(string[] args)
{
var collection = new List<A>();
ASupplier(collection); // 1) OK
var filtered = collection.Where(IAConditionCreator("a")).ToList();
ASupplier(filtered); // 2) NOT OK
var filtered2 = collection.Where(FixedIACondition).ToList();
ASupplier(filtered2); // 3) OK
}
private static void ASupplier(IReadOnlyCollection<A> aCollection)
{
foreach (var a in aCollection)
{
Console.WriteLine(a.GetText());
}
}
private static Func<IA, bool> IAConditionCreator(string value)
{
return a => a.GetText() == value;
}
private static bool FixedIACondition(IA ia) => ia.GetText() == "aa";
}
public interface IA
{
string GetText();
}
public class A : IA
{
public string GetText()
{
return "ABC";
}
}
}
编译器执行隐式类型转换的方式对于委托对象和方法组是不同的,我想它的主要目标是尽可能减少类型转换(包括隐式类型转换(的数量。
方法 FixedIACondition
作为编译器无论如何都必须转换为委托对象的方法组引用。编译能够推断出这个方法组可以转换成一个Func<A, bool>
,这是.Where
所需要的类型。
对于IAConditionCreator
,编译器已经有一个委托对象,现在尝试将该对象放入调用中。但是,它必须将集合转换为IEnumerable<IA>
或将委托转换为Func<A, bool>
。在 .NET 中对协变委托的支持不是很好(尝试调用 Delegate.Combine
(,我想编译器团队已经意识到了这一点,因此试图避免这种情况,而是进行第一次转换。
更改方法ASupplier
以接收 IASupplier 可解决此问题:
private static void ASupplier(IReadOnlyCollection<IA> aCollection)
{
foreach (var a in aCollection)
{
Console.WriteLine(a.GetText());
}
}
如果您只关心界面,这可能是您想要的。如果 Aupplier 仅用于处理类型 A,则可以从列表中强制转换或过滤那些 OfType A
ASupplier(filtered.OfType<A>().ToList()); // this will filter the list to return those of type A
ASupplier(filtered.Cast<A>().ToList()); // this will throw exception if any object can't be cast to A
另一种选择是强制转换 Func 本身以返回所需的类型:
var condition = (Func<A, bool>)IAConditionCreator("a");
var filtered = collection.Where(condition).ToList();
ASupplier(filtered);
还有其他方法可以处理多态性,但随后必须更具体地了解方案。