33/// <inheritdoc cref="ISpecification{T, TResult}"/>
44public class Specification < T , TResult > : Specification < T > , ISpecification < T , TResult >
55{
6- public new virtual ISpecificationBuilder < T , TResult > Query { get ; }
7-
8- public Specification ( )
9- : this ( InMemorySpecificationEvaluator . Default )
10- {
11- }
12-
13- public Specification ( IInMemorySpecificationEvaluator inMemorySpecificationEvaluator )
14- : base ( inMemorySpecificationEvaluator )
15- {
16- Query = new SpecificationBuilder < T , TResult > ( this ) ;
17- }
18-
19- public new virtual IEnumerable < TResult > Evaluate ( IEnumerable < T > entities )
20- {
21- return Evaluator . Evaluate ( entities , this ) ;
22- }
6+ public new ISpecificationBuilder < T , TResult > Query => new SpecificationBuilder < T , TResult > ( this ) ;
237
248 /// <inheritdoc/>
259 public Expression < Func < T , TResult > > ? Selector { get ; internal set ; }
@@ -29,93 +13,102 @@ public Specification(IInMemorySpecificationEvaluator inMemorySpecificationEvalua
2913
3014 /// <inheritdoc/>
3115 public new Func < IEnumerable < TResult > , IEnumerable < TResult > > ? PostProcessingAction { get ; internal set ; } = null ;
16+
17+ public new virtual IEnumerable < TResult > Evaluate ( IEnumerable < T > entities )
18+ {
19+ var evaluator = Evaluator ;
20+ return evaluator . Evaluate ( entities , this ) ;
21+ }
3222}
3323
3424/// <inheritdoc cref="ISpecification{T}"/>
3525public class Specification < T > : ISpecification < T >
3626{
37- protected IInMemorySpecificationEvaluator Evaluator { get ; }
38- protected ISpecificationValidator Validator { get ; }
39- public virtual ISpecificationBuilder < T > Query { get ; }
27+ // The state is null initially, but we're spending 8 bytes per reference (on x64).
28+ // This will be reconsidered for version 10 where we may store the whole state as a single array of structs.
29+ private List < WhereExpressionInfo < T > > ? _whereExpressions ;
30+ private List < SearchExpressionInfo < T > > ? _searchExpressions ;
31+ private List < OrderExpressionInfo < T > > ? _orderExpressions ;
32+ private List < IncludeExpressionInfo > ? _includeExpressions ;
33+ private List < string > ? _includeStrings ;
34+ private Dictionary < string , object > ? _items ;
4035
41- public Specification ( )
42- : this ( InMemorySpecificationEvaluator . Default , SpecificationValidator . Default )
43- {
44- }
36+ public ISpecificationBuilder < T > Query => new SpecificationBuilder < T > ( this ) ;
37+ protected virtual IInMemorySpecificationEvaluator Evaluator => InMemorySpecificationEvaluator . Default ;
38+ protected virtual ISpecificationValidator Validator => SpecificationValidator . Default ;
4539
46- public Specification ( IInMemorySpecificationEvaluator inMemorySpecificationEvaluator )
47- : this ( inMemorySpecificationEvaluator , SpecificationValidator . Default )
48- {
49- }
50-
51- public Specification ( ISpecificationValidator specificationValidator )
52- : this ( InMemorySpecificationEvaluator . Default , specificationValidator )
53- {
54- }
55-
56- public Specification ( IInMemorySpecificationEvaluator inMemorySpecificationEvaluator , ISpecificationValidator specificationValidator )
57- {
58- Evaluator = inMemorySpecificationEvaluator ;
59- Validator = specificationValidator ;
60- Query = new SpecificationBuilder < T > ( this ) ;
61- }
40+ /// <inheritdoc/>
41+ public Func < IEnumerable < T > , IEnumerable < T > > ? PostProcessingAction { get ; internal set ; }
6242
6343 /// <inheritdoc/>
64- public virtual IEnumerable < T > Evaluate ( IEnumerable < T > entities )
65- {
66- return Evaluator . Evaluate ( entities , this ) ;
67- }
44+ public string ? CacheKey { get ; internal set ; }
6845
6946 /// <inheritdoc/>
70- public virtual bool IsSatisfiedBy ( T entity )
71- {
72- return Validator . IsValid ( entity , this ) ;
73- }
47+ public bool CacheEnabled => CacheKey is not null ;
7448
7549 /// <inheritdoc/>
76- public IDictionary < string , object > Items { get ; set ; } = new Dictionary < string , object > ( ) ;
50+ public int Take { get ; internal set ; } = - 1 ;
7751
7852 /// <inheritdoc/>
79- public IEnumerable < WhereExpressionInfo < T > > WhereExpressions { get ; } = new List < WhereExpressionInfo < T > > ( ) ;
53+ public int Skip { get ; internal set ; } = - 1 ;
54+
8055
81- public IEnumerable < OrderExpressionInfo < T > > OrderExpressions { get ; } = new List < OrderExpressionInfo < T > > ( ) ;
56+ // We may store all the flags in a single byte. But, based on the object alignment of 8 bytes, we won't save any space anyway.
57+ // And we'll have unnecessary overhead with enum flags for now. This will be reconsidered for version 10.
58+ // Based on the alignment of 8 bytes (on x64) we can store 8 flags here. So, we have space for 3 more flags for free.
8259
8360 /// <inheritdoc/>
84- public IEnumerable < IncludeExpressionInfo > IncludeExpressions { get ; } = new List < IncludeExpressionInfo > ( ) ;
61+ public bool IgnoreQueryFilters { get ; internal set ; } = false ;
8562
8663 /// <inheritdoc/>
87- public IEnumerable < string > IncludeStrings { get ; } = new List < string > ( ) ;
64+ public bool AsSplitQuery { get ; internal set ; } = false ;
8865
8966 /// <inheritdoc/>
90- public IEnumerable < SearchExpressionInfo < T > > SearchCriterias { get ; } = new List < SearchExpressionInfo < T > > ( ) ;
67+ public bool AsNoTracking { get ; internal set ; } = false ;
9168
9269 /// <inheritdoc/>
93- public int ? Take { get ; internal set ; } = null ;
70+ public bool AsTracking { get ; internal set ; } = false ;
9471
9572 /// <inheritdoc/>
96- public int ? Skip { get ; internal set ; } = null ;
73+ public bool AsNoTrackingWithIdentityResolution { get ; internal set ; } = false ;
74+
75+
76+ // Specs are not intended to be thread-safe, so we don't need to worry about thread-safety here.
77+ internal void Add ( WhereExpressionInfo < T > whereExpression ) => ( _whereExpressions ??= new ( 2 ) ) . Add ( whereExpression ) ;
78+ internal void Add ( SearchExpressionInfo < T > searchExpression ) => ( _searchExpressions ??= new ( 2 ) ) . Add ( searchExpression ) ;
79+ internal void Add ( OrderExpressionInfo < T > orderExpression ) => ( _orderExpressions ??= new ( 2 ) ) . Add ( orderExpression ) ;
80+ internal void Add ( IncludeExpressionInfo includeExpression ) => ( _includeExpressions ??= new ( 2 ) ) . Add ( includeExpression ) ;
81+ internal void Add ( string includeString ) => ( _includeStrings ??= new ( 1 ) ) . Add ( includeString ) ;
9782
9883 /// <inheritdoc/>
99- public Func < IEnumerable < T > , IEnumerable < T > > ? PostProcessingAction { get ; internal set ; } = null ;
84+ public Dictionary < string , object > Items => _items ??= [ ] ;
10085
10186 /// <inheritdoc/>
102- public string ? CacheKey { get ; internal set ; }
87+ public IEnumerable < WhereExpressionInfo < T > > WhereExpressions => _whereExpressions ?? Enumerable . Empty < WhereExpressionInfo < T > > ( ) ;
10388
10489 /// <inheritdoc/>
105- public bool CacheEnabled { get ; internal set ; }
90+ public IEnumerable < SearchExpressionInfo < T > > SearchCriterias => _searchExpressions ?? Enumerable . Empty < SearchExpressionInfo < T > > ( ) ;
10691
10792 /// <inheritdoc/>
108- public bool AsTracking { get ; internal set ; } = false ;
93+ public IEnumerable < OrderExpressionInfo < T > > OrderExpressions => _orderExpressions ?? Enumerable . Empty < OrderExpressionInfo < T > > ( ) ;
10994
11095 /// <inheritdoc/>
111- public bool AsNoTracking { get ; internal set ; } = false ;
96+ public IEnumerable < IncludeExpressionInfo > IncludeExpressions => _includeExpressions ?? Enumerable . Empty < IncludeExpressionInfo > ( ) ;
11297
11398 /// <inheritdoc/>
114- public bool AsSplitQuery { get ; internal set ; } = false ;
99+ public IEnumerable < string > IncludeStrings => _includeStrings ?? Enumerable . Empty < string > ( ) ;
115100
116101 /// <inheritdoc/>
117- public bool AsNoTrackingWithIdentityResolution { get ; internal set ; } = false ;
102+ public virtual IEnumerable < T > Evaluate ( IEnumerable < T > entities )
103+ {
104+ var evaluator = Evaluator ;
105+ return evaluator . Evaluate ( entities , this ) ;
106+ }
118107
119108 /// <inheritdoc/>
120- public bool IgnoreQueryFilters { get ; internal set ; } = false ;
109+ public virtual bool IsSatisfiedBy ( T entity )
110+ {
111+ var validator = Validator ;
112+ return validator . IsValid ( entity , this ) ;
113+ }
121114}
0 commit comments