/
EnumerableQuery.cs
130 lines (105 loc) · 4.82 KB
/
EnumerableQuery.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
namespace System.Linq
{
public abstract class EnumerableQuery
{
internal abstract Expression Expression { get; }
internal abstract IEnumerable? Enumerable { get; }
internal EnumerableQuery() { }
[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal static IQueryable Create(Type elementType, IEnumerable sequence)
{
Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType);
return (IQueryable)Activator.CreateInstance(seqType, sequence)!;
}
[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
internal static IQueryable Create(Type elementType, Expression expression)
{
Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType);
return (IQueryable)Activator.CreateInstance(seqType, expression)!;
}
}
[RequiresDynamicCode(Queryable.InMemoryQueryableExtensionMethodsRequiresDynamicCode)]
[RequiresUnreferencedCode(Queryable.InMemoryQueryableExtensionMethodsRequiresUnreferencedCode)]
public class EnumerableQuery<T> : EnumerableQuery, IOrderedQueryable<T>, IQueryProvider
{
private readonly Expression _expression;
private IEnumerable<T>? _enumerable;
IQueryProvider IQueryable.Provider => this;
public EnumerableQuery(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
_expression = Expression.Constant(this);
}
public EnumerableQuery(Expression expression)
{
_expression = expression;
}
internal override Expression Expression => _expression;
internal override IEnumerable? Enumerable => _enumerable;
Expression IQueryable.Expression => _expression;
Type IQueryable.ElementType => typeof(T);
IQueryable IQueryProvider.CreateQuery(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);
Type? iqType = TypeHelper.FindGenericType(typeof(IQueryable<>), expression.Type);
if (iqType == null)
throw Error.ArgumentNotValid(nameof(expression));
return Create(iqType.GetGenericArguments()[0], expression);
}
IQueryable<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);
if (!typeof(IQueryable<TElement>).IsAssignableFrom(expression.Type))
{
throw Error.ArgumentNotValid(nameof(expression));
}
return new EnumerableQuery<TElement>(expression);
}
object? IQueryProvider.Execute(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);
return EnumerableExecutor.Create(expression).ExecuteBoxed();
}
TElement IQueryProvider.Execute<TElement>(Expression expression)
{
ArgumentNullException.ThrowIfNull(expression);
if (!typeof(TElement).IsAssignableFrom(expression.Type))
throw Error.ArgumentNotValid(nameof(expression));
return new EnumerableExecutor<TElement>(expression).Execute();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
private IEnumerator<T> GetEnumerator()
{
if (_enumerable == null)
{
EnumerableRewriter rewriter = new EnumerableRewriter();
Expression body = rewriter.Visit(_expression);
Expression<Func<IEnumerable<T>>> f = Expression.Lambda<Func<IEnumerable<T>>>(body, (IEnumerable<ParameterExpression>?)null);
IEnumerable<T> enumerable = f.Compile()();
if (enumerable == this)
throw Error.EnumeratingNullEnumerableExpression();
_enumerable = enumerable;
}
return _enumerable.GetEnumerator();
}
public override string? ToString()
{
if (_expression is ConstantExpression c && c.Value == this)
{
if (_enumerable != null)
return _enumerable.ToString();
return "null";
}
return _expression.ToString();
}
}
}