使用 Linq ExceptBy 函数在泛型 class 中出现奇怪的编译器错误
Weird compiler error in generic class using the Linq ExceptBy function
我有以下代码(从我的生产代码中提取),它应该编译但没有:
public class TestClass
{
public abstract class LocalizableEntity<TLocalizedEntity> where TLocalizedEntity : class, ILocalizedData, new()
{
public abstract string Id { get; set; } // Primary key
public abstract List<TLocalizedEntity> LocalizedData { get; set; }
}
public interface ILocalizedData
{
string CultureName { get; set; }
}
public void MergeData<TEntity, TLocalizedEntity>(IEnumerable<TEntity> newItems)
where TEntity : LocalizableEntity<TLocalizedEntity>
where TLocalizedEntity : class, ILocalizedData, new()
{
// Get the existing items
var existingItems = new List<TEntity>();
// Get the deleted items
var deletedItems = existingItems
.ExceptBy(newItems, x => x.Id, StringComparer.InvariantCultureIgnoreCase);
}
}
问题是 Linq ExceptBy
函数在通用输入类型上阻塞。如所写,该行给我一个编译器错误,突出显示 ExceptBy
并表示它无法从用法中推断出泛型类型参数。
The type arguments for method 'Enumerable.ExceptBy<TSource, TKey>(IEnumerable<TSource>, IEnumerable<TKey>, Func<TSource, TKey>, IEqualityComparer<TKey>?)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
如果我修改有问题的语句以指定通用类型,我会得到一个不同的错误:
var deletedItems = existingItems
.ExceptBy<TEntity, string>(newItems, x => x.Id, StringComparer.InvariantCultureIgnoreCase);
现在编译器突出显示 existingItems
变量并抱怨:
'List' does not contain a definition for 'ExceptBy' and the best extension method overload 'Queryable.ExceptBy<TEntity, string>(IQueryable<TEntity>, IEnumerable<string>, Expression<Func<TEntity, string>>, IEqualityComparer<string>?)'
requires a receiver of type 'IQueryable'
好的,我不知道这个错误消息中的“接收者”是什么,但它似乎在抱怨 existingItems
没有实现 IQueryable
,所以我添加 .AsQueryable
像这样:
var deletedItems = existingItems
.AsQueryable()
.ExceptBy<TEntity, string>(newItems, x => x.Id, StringComparer.InvariantCultureIgnoreCase);
现在它认为 newItems
是一个 IEnumerable<string>
( 不是 一个 IEnumerable<TEntity>
)并且它抱怨它无法转换从 IEnumerable<TEntity>
到 IEnumerable<string>
我放弃了。我是不是做错了什么,或者编译器只是被复杂的泛型类型搞糊涂了?
ExceptBy
期望第二个参数(this
source enumerable 之后的第一个参数)是键列表,而不是源对象列表。
所以你需要以下内容
var deletedItems = existingItems
.ExceptBy(newItems.Select(x => x.Id), x => x.Id, StringComparer.InvariantCultureIgnoreCase)
您可以编写一个扩展函数来做同样的事情
public static IEnumerable<TSource> ExceptByKey<TSource, TKey> (
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey>? comparer = null)
=> first.ExceptBy(second.Select(keySelector), keySelector, comparer);
我有以下代码(从我的生产代码中提取),它应该编译但没有:
public class TestClass
{
public abstract class LocalizableEntity<TLocalizedEntity> where TLocalizedEntity : class, ILocalizedData, new()
{
public abstract string Id { get; set; } // Primary key
public abstract List<TLocalizedEntity> LocalizedData { get; set; }
}
public interface ILocalizedData
{
string CultureName { get; set; }
}
public void MergeData<TEntity, TLocalizedEntity>(IEnumerable<TEntity> newItems)
where TEntity : LocalizableEntity<TLocalizedEntity>
where TLocalizedEntity : class, ILocalizedData, new()
{
// Get the existing items
var existingItems = new List<TEntity>();
// Get the deleted items
var deletedItems = existingItems
.ExceptBy(newItems, x => x.Id, StringComparer.InvariantCultureIgnoreCase);
}
}
问题是 Linq ExceptBy
函数在通用输入类型上阻塞。如所写,该行给我一个编译器错误,突出显示 ExceptBy
并表示它无法从用法中推断出泛型类型参数。
The type arguments for method
'Enumerable.ExceptBy<TSource, TKey>(IEnumerable<TSource>, IEnumerable<TKey>, Func<TSource, TKey>, IEqualityComparer<TKey>?)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
如果我修改有问题的语句以指定通用类型,我会得到一个不同的错误:
var deletedItems = existingItems
.ExceptBy<TEntity, string>(newItems, x => x.Id, StringComparer.InvariantCultureIgnoreCase);
现在编译器突出显示 existingItems
变量并抱怨:
'List' does not contain a definition for 'ExceptBy' and the best extension method overload
'Queryable.ExceptBy<TEntity, string>(IQueryable<TEntity>, IEnumerable<string>, Expression<Func<TEntity, string>>, IEqualityComparer<string>?)'
requires a receiver of type 'IQueryable'
好的,我不知道这个错误消息中的“接收者”是什么,但它似乎在抱怨 existingItems
没有实现 IQueryable
,所以我添加 .AsQueryable
像这样:
var deletedItems = existingItems
.AsQueryable()
.ExceptBy<TEntity, string>(newItems, x => x.Id, StringComparer.InvariantCultureIgnoreCase);
现在它认为 newItems
是一个 IEnumerable<string>
( 不是 一个 IEnumerable<TEntity>
)并且它抱怨它无法转换从 IEnumerable<TEntity>
到 IEnumerable<string>
我放弃了。我是不是做错了什么,或者编译器只是被复杂的泛型类型搞糊涂了?
ExceptBy
期望第二个参数(this
source enumerable 之后的第一个参数)是键列表,而不是源对象列表。
所以你需要以下内容
var deletedItems = existingItems
.ExceptBy(newItems.Select(x => x.Id), x => x.Id, StringComparer.InvariantCultureIgnoreCase)
您可以编写一个扩展函数来做同样的事情
public static IEnumerable<TSource> ExceptByKey<TSource, TKey> (
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey>? comparer = null)
=> first.ExceptBy(second.Select(keySelector), keySelector, comparer);