C#具有泛型类型约束的多态性

时间:2017-02-08 00:53:58

标签: c# entity-framework linq generics

我正在为IQueryable<Item>创建一个扩展方法,其中Item是实体框架的实体。

extended方法返回第一行中的一个或多个属性值,如果未找到任何行或属性值为null,则返回null。

以下是代码:

internal static TResult FirstOrDefault<TResult>(this IQueryable<Item> items,
        Expression<Func<Item, TResult?>> selector, TResult defaultValue)
        where TResult : struct
{
    var ret = items.Select(selector).FirstOrDefault();

    if (ret == null || !ret.HasValue)
    {
        return defaultValue;
    }

    return ret.Value;
}

internal static TResult FirstOrDefault<TResult>(this IQueryable<Item> items,
        Expression<Func<Item, TResult>> selector, TResult defaultValue)
        where TResult : class
{
    return items.Select(selector).FirstOrDefault() ?? defaultValue;
}

由于属性可能具有值类型值,因此我决定为value-type和reference-type创建两个扩展方法。

但是当我使用这种方法时(见下文),

_dbContext.Items.Where(i => i.Id == '...').FirstOrDefault(i => i.Modified, DateTime.Now)

VS警告

  

类型'DateTime'必须是引用类型才能在泛型类型或方法'EFExtensions.FirstOrDefault(IQueryable,Expresion&gt;,TResult)'中将其用作参数'TResult'

我知道这意味着VS尝试使用第二个扩展方法编译此方法,而 DateTime 将违反where TResult : class约束。

如何在不修改方法名称的情况下让VS使用第一个

或者有没有更好的方法来实现我的目标?

任何答案都将不胜感激。

谢谢:)

1 个答案:

答案 0 :(得分:2)

在第一种方法中,Expression的返回类型是可空的TResult,所以您需要做的就是返回它。这可以通过演员表来完成:

_dbContext.Items
    .Where(i => i.Id == '...')
    .FirstOrDefault(i => (DateTime?)i.Modified, DateTime.Now);