c# - IEnumerable、lambda协方差和扩展方法
问题描述
我有一个扩展方法来过滤实现接口的类型,使用谓词将参数输入到该接口:
public interface ILifeTrack
{
DateTimeOffset? CreatedOn { get; set; }
DateTimeOffset? ModifiedOn { get; set; }
DateTimeOffset? DeletedOn { get; set; }
}
public class LifeTrack : ILifeTrack
{
public static Expression<Func<T, Boolean>> GetIsActiveExpression<T>()
where T : ILifeTrack
{
return e => e.CreatedOn != null && e.DeletedOn == null;
}
public static readonly Expression<Func<ILifeTrack, Boolean>> isActiveExpression;
public static readonly Func<ILifeTrack, Boolean> isActiveFunc;
static LifeTrack()
{
isActiveExpression = GetIsActiveExpression<ILifeTrack>();
isActiveFunc = isActiveExpression.Compile();
}
public DateTimeOffset? CreatedOn { get; set; }
public DateTimeOffset? ModifiedOn { get; set; }
public DateTimeOffset? DeletedOn { get; set; }
}
public static class IEnumerableOfILifeTrackExtensions
{
public static IEnumerable<T> MetadataActive<T>(this IEnumerable<T> instance)
where T : class, ILifeTrack
{
return instance.Where(LifeTrack.isActiveFunc);
}
}
但是在使用扩展方法时,会引发异常以指示源 IEnumerable<> 为空:
System.ArgumentNullException: Value cannot be null.
Parameter name: source
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
...
我确定传递给扩展方法的实例不为空,因为这些替代形式按预期工作:
instance.Where<T, T>(LifeTrack.isActiveFunc);
instance.Where(e => LifeTrack.isActiveFunc.Invoke(e));
Enumerable.Where<T>(instance, LifeTrack.isActiveFunc);
VS 表明
instance.Where(LifeTrack.isActiveFunc)
被推断为
instance.Where<T, ILifeTrack>(LifeTrack.isActiveFunc)
现在我认为在内部涉及一些强制转换,并且在某个点向下转换失败导致空引用,但幕后真正发生了什么?
madreflection 是对的,我有以下扩展方法,试图克服同样的问题:
public static IEnumerable<T> Where<T, TI>(this IEnumerable<T> instance, Func<TI, bool> predicate)
where T : class, TI
{
return Enumerable.Where(instance, predicate) as IEnumerable<T>;
}
我自己的严重疏忽,但是处理在 .Where 中使用协变 Func 的问题的正确方法是什么?
我认为应该是
instance.Where<T>(LifeTrack.isActiveFunc)
但我仍然不明白为什么它需要显式输入。
解决方案
推荐阅读
- css - 如何在菜单选项后面制作三角形悬停效果
- python - 您将如何使用给定的输入树递归地计算二叉树的总和?
- google-apps-script - 学生填写 Google 表格时的教师表格通知
- react-native - 有没有办法在不使用 View 的情况下为组件指定默认样式?
- c++ - 如何从 C++ 中的模板类访问 std::vector 数据
- fortran - 未复制 Fortran 派生类型的指针成员
- jestjs - 使用 jest.run() 或 jest.runCLI() 运行所有测试或以编程方式运行 jest
- c - 如何在 C 中为 scanf 添加循环?
- android - 错误 INSTALL_PARSE_FAILED_MANIFEST_MALFORMED
- python - Nested XML parsing using python Element Tree or Minidom