【问题标题】:Specifying deferred action before IQueryable has been evaluated在评估 IQueryable 之前指定延迟操作
【发布时间】:2015-02-25 12:37:45
【问题描述】:

我想对从IQueryable 返回的实体执行一些后处理,但我想在评估查询之前指定后处理。比如:

IQueryable<Client> GetClients()
{
    return _context.Set<Client>()
        .PostProcess(c => c.MobileNumber = c.MobileNumber.Replace(" ", ""));
}

Client GetClient(int id)
{
    return GetClients()
        .FirstOrDefault(c => c.Id == id);
}

在上面的示例中,我希望从上述两种方法返回的每个 Client 都从其手机号码中删除所有空格。这可能吗?

【问题讨论】:

    标签: c# linq iqueryable


    【解决方案1】:

    编辑:这是个坏主意

    它适用于 OP 中所述的简单情况,但任何进一步的 IQueryable 扩展(例如 .Where() 子句)都将丢弃后处理行为。我不确定在技术上是否可以做我想做的事,现在我想起来了,我什至不确定语义会超出简单的情况。尽管如此,简单的案例仍然有效,并且非常方便保持流畅......


    原文:

    我想我会分享我的方法,以防有人发现它有用(或评论为什么这是一个坏主意)。该解决方案使用两个装饰器将后处理操作推迟到执行查询,并使用扩展方法来设置它们:

    public static class QueryableExtensions
    {
        public static IQueryable<T> PostProcess<T>(this IQueryable<T> source, Action<T> postProcessor) where T : class
        {
            return new QueryableWrapper<T>(source, postProcessor);
        }
    
        // wraps IQueryProvider.Execute methods with post-processing action
        class QueryProviderWrapper<T> : IQueryProvider where T : class
        {
            private readonly IQueryProvider _wrapped;
            private readonly Action<T> _postProcessor;
    
            public QueryProviderWrapper(IQueryProvider wrapped, Action<T> postProcessor)
            {
                _wrapped = wrapped;
                _postProcessor = postProcessor;
            }
    
            public IQueryable CreateQuery(Expression expression)
            {
                return _wrapped.CreateQuery(expression);
            }
    
            public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
            {
                return _wrapped.CreateQuery<TElement>(expression);
            }
    
            public object Execute(Expression expression)
            {
                var result = _wrapped.Execute(expression);
                var asT = result as T;
                if (asT != null)
                    _postProcessor(asT);
                return result;
            }
    
            public TResult Execute<TResult>(Expression expression)
            {
                var result = _wrapped.Execute<TResult>(expression);
                var asT = result as T;
                if (asT != null)
                    _postProcessor(asT);
                return result;
            }
        }
    
        // wraps IQueryable.GetEnumerator() with post-processing action
        class QueryableWrapper<T> : IQueryable<T> where T : class
        {
            private readonly IQueryable<T> _wrapped;
            private readonly Action<T> _postProcessor;
            private readonly IQueryProvider _provider;
    
            public QueryableWrapper(IQueryable<T> wrapped, Action<T> postProcessor)
            {
                _wrapped = wrapped;
                _postProcessor = postProcessor;
                _provider = new QueryProviderWrapper<T>(_wrapped.Provider, postProcessor);
            }
    
            public Expression Expression
            {
                get { return _wrapped.Expression; }
            }
    
            public Type ElementType
            {
                get { return _wrapped.ElementType; }
            }
    
            public IQueryProvider Provider
            {
                get { return _provider; }
            }
    
            public IEnumerator<T> GetEnumerator()
            {
                return _wrapped
                    .AsEnumerable()
                    .Do(_postProcessor)
                    .GetEnumerator();
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }
    }
    

    GetEnumerator() 装饰器使用来自Interactive Extensions.Do() 扩展方法,就像SelectForEach 之间的交叉:它被延迟调用,但接受Action&lt;T&gt; 并返回T

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      相关资源
      最近更新 更多