有什么重要的理由可以避免“像IQueryable一样”吗?

时间:2015-07-05 10:25:04

标签: c# casting iqueryable

我有一个模型到视图模型的映射扩展方法库。支持它们是一个基类,有一些常用方法,包括Transform,下面是:

internal abstract class TransformBase<TOriginal, TConverted>
{
    protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }

    public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
    {
        var queryable = value as IQueryable<TOriginal> ?? value.AsQueryable();
        return queryable.Select(Expression);
    }

我的问题:是否有任何重要原因,除了可以忽略的性能影响之外,我应该避免上面的as IQueryable演员?例如,我可以改为执行以下操作:

internal abstract class TransformBase<TOriginal, TConverted>
{
    protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }

    public IQueryable<TConverted> Transform(IQueryable<TOriginal> value)
    {
        return value.Select(Expression);
    }

    public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
    {
        return value.AsQueryable().Select(Expression);
    }

...但我宁愿不必在每个依赖类中编写重载。编辑:澄清一下,这是我要避免的一个例子:

public static class TransformCompany
{
    private static readonly TransformBase<Organization, CompanyHeader> header = new TransformPrecompiled<Organization, CompanyHeader>(
    company => new CompanyHeader
    {
        Name = company.Name,
    });

    public static IQueryable<CompanyHeader> AsHeaders(this IQueryable<Organization> companies)
    {
        return header.Transform(companies);
    }

    // Note I have to include this capability in each of my dependent classes
    // Worse is the possibility that someone may accidentally implement
    // only IEnumerable for a future model transformation,
    // causing a hidden data performance problem
    public static IQueryable<CompanyHeader> AsHeaders(this IEnumerable<Organization> companies)
    {
        return header.Transform(companies);
    }

2 个答案:

答案 0 :(得分:1)

Queryable.AsQueryable Method (IEnumerable)

  

如果源的类型实现了IQueryable,   AsQueryable(IEnumerable)直接返回它。否则,它返回一个   IQueryable通过调用等效查询来执行查询   Enumerable中的operator方法,而不是Queryable中的方法。

而不是将您的Transform方法简化为

return value.AsQueryable().Select(Expression);

答案 1 :(得分:1)

我认为您不需要IEnumerable<T>IQueryable<T>的单独扩展名,因为IQueryable<T>继承自IEnumerable<T>,您也不需要演员。

查看referencesourceAsQueryable()实际上会为您检查:

public static IQueryable<TElement> AsQueryable<TElement>(this IEnumerable<TElement> source)
{
    if (source == null)
        throw Error.ArgumentNull("source");
    if (source is IQueryable<TElement>)
        return (IQueryable<TElement>)source;
    return new EnumerableQuery<TElement>(source);
}

因此,以下内容应该对您没有任何影响:

internal abstract class TransformBase<TOriginal, TConverted>
{
    protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }

    public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
    {
        return value.AsQueryable().Select(Expression);
    }
}


public static class TransformCompany
{
    public static IQueryable<CompanyHeader> AsHeaders(this IEnumerable<Organization> companies)
    {
        return header.Transform(companies);
    }
}