ASP.NET рдХреЛрд░ рдореЗрдВ рдЧреНрд▓реЛрдмрд▓ рдХреНрд╡реЗрд░реА рдкрд░рд┐рдгрд╛рдо рдХреИрд╢рд┐рдВрдЧ

рдПрдХ рд░реВрдк рдореЗрдВ CQRS рдкреНрд░рддрд┐рдорд╛рди рдпрд╛ рдХреЛрдИ рдЕрдиреНрдп рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдХреНрд╡реЗрд░реА рдХреЙрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдирд╣реАрдВ рдмрджрд▓реЗрдЧреАред рдпрд╣реА рд╣реИ, рдПрдХ рд╣реА рдХреНрд╡реЗрд░реА рдХреЗ рднреАрддрд░ рдПрдХ рд╣реА рдХреНрд╡реЗрд░реА рдХреЗ рд▓рд┐рдП рдХрдИ рдХреЙрд▓ рдХрд╛ рдПрдХ рд╣реА рдкрд░рд┐рдгрд╛рдо рд╣реЛрдЧрд╛ред


рдХреНрд╡реЗрд░реА рдХреЗ рднрд╛рдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд╕рднреА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ IQuery рдпрд╛ IAsyncQuery рдкреНрд░рдХрд╛рд░ рдХреЗ рд╣реЛрддреЗ рд╣реИрдВ:


public interface IQuery<TIn, TOut> { TOut Query(TIn input); } public interface IAsyncQuery<TIn, TOut>: IQuery<TIn, Task<TOut> { } 

рдпреЗ рдЗрдВрдЯрд░рдлреЗрд╕ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдбреЗрдЯрд╛ рдХреА рдкреНрд░рд╛рдкреНрддрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЦрд╛рддреЗ рдХреА рдЫреВрдЯ / рдмреЛрдирд╕ рдФрд░ рдмрд╛рдХреА рд╕рдм рдореЗрдВ рд╕реНрд╡рд░реВрдкрд┐рдд рдХреАрдорддреЛрдВ рдХреА рдкреНрд░рд╛рдкреНрддрд┐:


 public class ProductPriceQuery: IQuery<ProductDto,PricePresentationDto> { public ProductPriceQuery( IQuery<ProductDto, PriceWithSalesDto> priceWithSalesQuery, IQuery<PriceWithSalesDto, PricePresentationDto> pricePresentationQuery) { _priceWithSalesQuery = priceWithSalesQuery; _pricePresentationQuery = pricePresentationQuery; } public PricePresentationDto Query(ProductDto dto) { var withSales = _priceWithSalesQuery(dto); var result = _pricePresentationQuery(withSales); return result; } } 

рдкрд╛рдЗрдк рд▓рд╛рдЗрди рдЗрдВрдЯрд░рдлреЗрд╕


рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рд▓рд╛рдн рдЖрд╡реЗрджрди рдореЗрдВ рдЗрдВрдЯрд░рдлреЗрд╕ рдХреА рдПрдХрд░реВрдкрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


 public class Aggregate2Query<TIn, TOut1, TOut2> : BaseAggregateQuery<TIn, TOut2> { public Aggregate2Query( IQuery<TIn, TOut1> query0, IQuery<TOut1, TOut2> query1) : base(query0, query1){} } public abstract class BaseAggregateQuery<TIn, TOut> : IQuery<TIn, TOut> { private object[] queries { get; set; } protected BaseAggregateQuery(params object[] queries) { this.queries = queries; } public TOut Query(TIn input) => queries.Aggregate<object, dynamic>(input, (current, query) => ((dynamic) query).Query(current)); } 

рдЗрд╕ рддрд░рд╣ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВ:


 serviceCollection.AddScoped(typeof(Aggregate2Query<,,>)); 

рд╣рдореЗрдВ рдорд┐рд▓рддрд╛ рд╣реИ:


 public ProductPriceQuery( BaseAggregateQuery<ProductDto,PriceWithSalesDto,PricePresentationDto> query) { _aggregateQuery = query; } public PricePresentationDto Query(ProductDto dto) => _aggregateQuery.Query(dto); 

рдЖрджрд░реНрд╢ рд░реВрдк рд╕реЗ, рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЛ рдирд┐рд░реНрдорд╛рддрд╛ рдХреА рдПрдХ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдореЗрдВ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рдЧреМрд░рд╡ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реБрдВрджрд░ рдЪрд╛рд▓ рд╣реИред


рд╕рдЬреНрдЬрд╛рдХрд╛рд░ рдФрд░ ASP.NET рдХреЛрд░


MediatR рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЗрдВрдЯрд░рдлреЗрд╕ рдХреА рдПрдХрд░реВрдкрддрд╛ рдФрд░ рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдкрд░ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред


рд╕рдЬреНрдЬрд╛рдХрд╛рд░ рдЖрдкрдХреЛ рдорд╛рдирдХ IQuery <TIn, TOut> рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рдЯрдХрд╛ рджреЗрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рд▓реЙрдЧрд┐рдВрдЧ:


 public class LoggingQuery<TIn,TOut>: IQuery<TIn,TOut> { public LoggingQuery(IQuery<TIn,TOut> priceQuery) { _priceQuery = priceQuery } public TOut Query(TIn input) { Console.WriteLine($"Query {_priceQuery.GetType()} Start"); var result= _priceQuery.Query(input); Console.WriteLine($"Query {_priceQuery.GetType()} End"); return result; } } 

рдореИрдВ рдЗрд╕ рддрдереНрдп рдХреЛ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ рдХрд┐ рд╕рдЬреНрдЬрд╛рдХрд╛рд░ рдЖрдкрдХреЛ рдкреВрд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рдлреИрд▓рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдПрдХ рд╕реНрдерд╛рди рдкрд░ рдХреНрд░реЙрд╕-рдХрдЯрд┐рдВрдЧ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд▓рд┐рдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рдпрд╣ рдЗрд╕ рд▓реЗрдЦ рдХреЗ рджрд╛рдпрд░реЗ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдирд╣реАрдВ рд╣реИред


.Net рдХреЛрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдорд╛рдирдХ IoC рдХрдВрдЯреЗрдирд░ рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реИред рдХрдард┐рдирд╛рдИ рдпрд╣ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╣реА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИрдВ: рдореВрд▓ рдХреНрд╡реЗрд░реА рдФрд░ рдбреЗрдХреЛрд░реЗрдЯрд░, рдФрд░ рдПрдХ рд╣реА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЬреЛ рдбреЗрдХреЛрд░реЗрдЯрд░ рдЗрдореНрдкреНрд▓рд╛рдВрдЯреНрд╕ рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИред рдХрдВрдЯреЗрдирд░ рдРрд╕реЗ рдЧреНрд░рд╛рдлрд╝ рдХреЛ рд╣рд▓ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ "рдкрд░рд┐рдкрддреНрд░ рдирд┐рд░реНрднрд░рддрд╛" рддреНрд░реБрдЯрд┐ рдлреЗрдВрдХрддрд╛ рд╣реИред


рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рдХрдИ рддрд░реАрдХреЗ рд╣реИрдВред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ .Net рдХреЛрд░ рдХрдВрдЯреЗрдирд░ рдХреЗ рд▓рд┐рдП, рд╕реНрдХреНрд░реВрдЯреЛрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд▓рд┐рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣ рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ:


  services.Decorate(typeof(IQuery<,>), typeof(LoggingQuery<,>)); 

рдпрджрд┐ рдЖрдк рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдирд┐рд░реНрднрд░рддрд╛ рдирд╣реАрдВ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд╕реНрд╡рдпрдВ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдореИрдВрдиреЗ рдХрд┐рдпрд╛ рдерд╛ред рдХреЛрдб рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдХреНрд╡реЗрд░реА рдХреЗ рднрд╛рдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрд╡реЗрд░реА рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдХреИрд╢рд┐рдВрдЧ рдХрд░рдиреЗ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдкрдХреЛ рдХреИрд╢рд┐рдВрдЧ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ рдХреБрдВрдЬреА рд╡рд░реНрдЧ рд╣реИ, рддреЛ рдЖрдкрдХреЛ GetHashCode рдФрд░ Equals рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рддреБрд▓рдирд╛ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд▓реЗрдВрдЧреЗред


рдХреИрд╢рд┐рдВрдЧ рддрд░реАрдХреЗ


рдореИрдВ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдХреИрд╢ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рд╕реНрддреБрдд рдХрд░реВрдВрдЧрд╛:


 //Cache ConcurrentDictionary<Key,Value> _cache { get; } //Key public class Key { //ReSharper-generated code protected bool Equals(Key other) { return Field1 == other.Field1 && Field2 == other.Field2; } //ReSharper-generated code public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((Key) obj); } //ReSharper-generated code public override int GetHashCode() { unchecked { return (Field1 * 397) ^ Field2; } } public int Field1 { get; set; } public int Field2 { get; set; } } //Value irrelevant 

рдПрдХ рдореВрд▓реНрдп рдХреА рдЦреЛрдЬ рдХрд░рддреЗ рд╕рдордп, GetHashCode рд╡рд┐рдзрд┐ рдХреЛ рдкрд╣рд▓реЗ рд╡рд╛рдВрдЫрд┐рдд рдЯреЛрдХрд░реА рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░, рдпрджрд┐ рдЯреЛрдХрд░реА рдореЗрдВ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рддрддреНрд╡ рд╣реИрдВ, рддреЛ рдмрд░рд╛рдмрд░ рдХреЛ рддреБрд▓рдирд╛ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рджреЗрдЦреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдЖрдк рдпрд╣ рдирд╣реАрдВ рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред


ReSharper рд╕реНрд╡рдпрдВ рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рд╡реИрд╢реНрд╡рд┐рдХ рд░реВрдк рд╕реЗ рдХреИрд╢рд┐рдВрдЧ рдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ IQuery <TIn, TOut> рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ, IQuery <TIn, TOut> рдЗрдВрдЯрд░рдлрд╝реЗрд╕, SRP рдХреЗ рд▓рд┐рдП рдордд рднреВрд▓рдирд╛ред рдЗрд╕рд▓рд┐рдП, рдкреБрдирд░реНрдкрд░рд┐ рджреНрд╡рд╛рд░рд╛ рддрд░реАрдХреЛрдВ рдХреА рдкреАрдврд╝реА рд╣рдореЗрдВ рд╢реЛрднрд╛ рдирд╣реАрдВ рджреЗрддреА рд╣реИред


рдЬрдм рд╣рдо рдПрдВрдб-рдЯреВ-рдПрдВрдб рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВ, рддреЛ рдПрдУрдкреА рдлреНрд░реЗрдорд╡рд░реНрдХ рдмрдЪрд╛рд╡ рдореЗрдВ рдЖрддреЗ рд╣реИрдВред EqualsFody, Fody рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд▓рдЧрдЗрди, IL рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддрд╛ рд╣реИ, EqualsAttribute рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рд╕рдорд╛рди рдФрд░ GetHashCode рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рддрд╛ рд╣реИред


рдЗрд╕ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд╕рд╛рде рдкреНрд░рддреНрдпреЗрдХ Dto рдХреЛ рдзреНрд╡рдЬрд╛рдВрдХрд┐рдд рдирд╣реАрдВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо IQuery рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рдереЛрдбрд╝рд╛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ


 public IQuery<TIn,TOut> where TIn : CachedDto{ } [Equals] public class CachedDto{ } 

рдЕрдм рд╕рднреА Dto рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рддрд░реАрдХреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВрдЧреЗ, рдФрд░ рд╣рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдЗрдирдкреБрдЯ DTO рдореЗрдВ рдПрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ (рдЗрд╕реЗ рдмреЗрд╕ рдХреНрд▓рд╛рд╕ рд╕реЗ рдЙрдард╛рдпрд╛ рдЬрд╛рдПрдЧрд╛)ред рдпрджрд┐ рдкреБрдирд░реНрд▓реЗрдЦрди рдЖрдИрдПрд▓ рдЖрдкрдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдирд╣реАрдВ рд╣реИ, рддреЛ рдХреИрд╢реНрдбреНрдЯреЛ рдХреЛ рдЗрд╕ рддрд░рд╣ рд▓рд╛рдЧреВ рдХрд░реЗрдВ (рдЙрд╕ рд╕рдВрджрд░реНрдн рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдЬрд┐рд╕рдореЗрдВ рдЖрдзрд╛рд░ рд╡рд░реНрдЧ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ):


 public class CachedDto{ public override bool Equals(object x) => DeepEquals.Equals(this,x); public override int GetHashCode() => DeepHash.GetHashCode(this); } 

DeepEquals.Equals рдФрд░ DeepHash.GetHashCode рдкреНрд░рддрд┐рдмрд┐рдВрдм рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдпрд╣ рдлрд╝реЛрдбреА рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдзреАрдорд╛ рд╣реЛрдЧрд╛, рдпрд╣ рдХреЙрд░реНрдкреЛрд░реЗрдЯ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдШрд╛рддрдХ рдирд╣реАрдВ рд╣реИред


рд▓реЗрдХрд┐рди SRP рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╛рдж рд░рдЦреЗрдВ, IQuery рдХреЛ рдпрд╣ рдирд╣реАрдВ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдпрд╣ рдХреИрд╢реНрдб рд╣реИред


рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди IEqualityComparer рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдбрд┐рдХреНрд╢рдирд░реА рдЗрд╕реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ рд▓реЗ рдЬрд╛рддреА рд╣реИ рдФрд░ рдЗрд╕реЗ рдбрд╛рд▓рдиреЗ / рд╣рдЯрд╛рдиреЗ / рдЦреЛрдЬ рдХрд░рдиреЗ рдкрд░ рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИред


  public class EqualityComparerUsingReflection<TKey> : IEqualityComparer<TKey> { public bool Equals(TKey x, TKey y) => DeepEqualsCommonType(x, y); public int GetHashCode(TKey obj) => Hash.GetHashCode(obj); } 

рдЕрдм рдЖрдк TIn рдкрд░ рдмрд╛рдзрд╛ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдордиреЗ рд╡рд╣ рд╣рд╛рд╕рд┐рд▓ рдХрд┐рдпрд╛ рдЬреЛ рд╣рдо рдЪрд╛рд╣рддреЗ рдереЗред рдЪрд▓реЛ рдПрдХ рдХреИрд╢рд┐рдВрдЧ рдбреЗрдХреЛрд░реЗрдЯрд░ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:


  public class BaseCacheQuery<TIn, TOut> : IQuery<TIn, TOut> { private readonly ConcurrentDictionary<TIn, TOut> _cache; private readonly IQuery<TIn, TOut> _query; protected BaseCacheQuery( IQuery<TIn, TOut> query, IConcurrentDictionaryFactory<TIn, TOut> factory) { _cache = factory.Create(); _query = query; } public TOut Query(TIn input) => _cache .GetOrAdd(input, x => _query.Query(input)); } 

IConcurrentDictionaryFactory рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ, рдЗрд╕ рдХрд╛рд░рдЦрд╛рдиреЗ рдХрд╛ рд▓рдХреНрд╖реНрдп рдбрд┐рдХреНрд╢рдирд░реА рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрдпреЛрдВ рди рдХреЗрд╡рд▓ рдЗрд╕реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ рдмрдирд╛рдпрд╛ рдЬрд╛рдП?


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, DI рдФрд░ SRP, рдпрд╣ рдХрд╛рдлреА рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдПрдХ рдФрд░ рддреБрд▓рдирд╛рддреНрдордХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдбреАрдЯреАрдУ рдХреЗ рдХреБрдЫ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдЖрд╕рд╛рди) рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ рдпрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐ рдРрд╕реА рд╕реНрдерд┐рддрд┐ рд╕рдВрднрд╡ рд╣реИ рдЬрдм рдкреНрд░рддрд┐рдмрд┐рдВрдм рдФрд░ рдЕрдореВрд░реНрдд рдХреЗ рдХрд╛рд░рдг рдХреИрд╢ рдзреАрдорд╛ рд╣реЛрдиреЗ рд▓рдЧреЗред рд▓реАрдХред рдореИрдВ рд╕рдордЭреМрддрд╛ рдХрд░реВрдВрдЧрд╛ рдФрд░ рдЕрдЧрд░ рдбреЛрдЯреЛ рдореЗрдВ рдмрд░рд╛рдмрд░реА рдХреА рдЫреВрдЯ рд╣реИ рдФрд░ рдЧреЗрдЯрд╢реЗрдбрдХреЛрдб тАЛтАЛ"рд╣реИрд╡реА" рдЗрдХреНрд╡реЗрд▓рд┐рдЯреА.рдХреЙрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред


рдХрд╛рд░рдЦрд╛рдиреЗ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдпрд╣ рдЬрд╛рдВрдЪрдирд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рддрд░реАрдХреЛрдВ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рдбреАрдЯреАрдУ рдореЗрдВ рдкреБрдирд░реНрдкрд░рд┐рднрд╛рд╖рд┐рдд рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдорд╛рдирдХ рд╢рдмреНрджрдХреЛрд╢ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдирд╣реАрдВ - рддреБрд▓рдирд┐рддреНрд░ рдХреЗ рд╕рд╛рде рдПрдХ рд╢рдмреНрджрдХреЛрд╢ред


рдкрдВрдЬреАрдХрд░рдг


рдЖрдЗрдП, рдпрд╣ рд╕рдм рдХреИрд╕реЗ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВред


ConfigureServices рд╡рд┐рдзрд┐ рдХреА рд╕реЗрд╡рд╛рдУрдВ рдХрд╛ рддрд░реНрдХ ServiceDescriptors рдХрд╛ рд╕рдВрдЧреНрд░рд╣ рд╣реИ, рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рд╡рд░рдгрдХ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ


 public class ServiceDescriptor{ // other methods /// <inheritdoc /> public ServiceLifetime Lifetime { get; } /// <inheritdoc /> public Type ServiceType { get; } /// <inheritdoc /> public Type ImplementationType { get; } /// <inheritdoc /> public object ImplementationInstance { get; } /// <inheritdoc /> public Func<IServiceProvider, object> ImplementationFactory { get; } // other methods } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, LifeTime = Scoped рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ ServiceDescriptor рд╕реЗрд╡рд╛ рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред
ServiceType = typeof (IService), ImplementType = typeof (рд╕реЗрд╡рд╛):


 services.AddScoped<IService,Service>(). 

рдЗрдореНрдкреНрд▓реАрдореЗрдВрдЯреЗрд╢рди рдлреИрдХреНрдЯреНрд░реА рдкреНрд░реЙрдкрд░реНрдЯреА рдЖрдкрдХреЛ рдирд┐рд░реНрднрд░рддрд╛ рдмрдирд╛рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ; рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдореИрдВ IServiceCollection рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд▓рд┐рдЦреВрдВрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рд╕рднреА IQuery рдФрд░ IAsyncQuery рд╡рд┐рдзрд╛рдирд╕рднрд╛рдУрдВ рдореЗрдВ рдорд┐рд▓реЗрдВрдЧреЗ, рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдХреЛ рд▓рдЯрдХрд╛рдПрдВрдЧреЗ рдФрд░ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВрдЧреЗред


  public static void AddCachedQueries(this IServiceCollection serviceCollection) { // Func<Type,bool>    IAsyncQuery var asyncQueryScanPredicate = AggregatePredicates( IsClass, ContainsAsyncQueryInterface); // Func<Type,bool>     IQuery var queryScanAssemblesPredicate =AggregatePredicates( IsClass, x => !asyncQueryScanPredicate(x), ContainsQueryInterface); //    IAsyncQuery    var asyncQueries = GetAssemblesTypes( asyncQueryScanPredicate, DestAsyncQuerySourceType); //    IQuery    var queries = GetAssemblesTypes( queryScanAssemblesPredicate, DestQuerySourceType); //   ConcurrentDictionary serviceCollection.AddScoped( typeof(IConcurrentDictionaryFactory<,>), typeof(ConcDictionaryFactory<,>)); //   services ServiceDescriptor'   IAsyncQuery serviceCollection.QueryDecorate(asyncQueries, typeof(AsyncQueryCache<,>)); //   services ServiceDescriptor'   IQuery serviceCollection.QueryDecorate(queries, typeof(QueryCache<,>)); } private static void QueryDecorate(this IServiceCollection serviceCollection, IEnumerable<(Type source, Type dest)> parameters, Type cacheType, ServiceLifetime lifeTime = ServiceLifetime.Scoped) { foreach (var (source, dest) in parameters) serviceCollection.AddDecorator( cacheType.MakeGenericType(source.GenericTypeArguments), source, dest, lifeTime); } private static void AddDecorator( this IServiceCollection serviceCollection, Type cacheType, Type querySourceType, Type queryDestType, ServiceLifetime lifetime = ServiceLifetime.Scoped) { //ReSharper disable once ConvertToLocalFunction Func<IServiceProvider, object> factory = provider => ActivatorUtilities.CreateInstance(provider, cacheType, ActivatorUtilities.GetServiceOrCreateInstance(provider, queryDestType)); serviceCollection.Add( new ServiceDescriptor(querySourceType, factory, lifetime)); } } 

AddDecorator рдкрджреНрдзрддрд┐ рд╡рд┐рд╢реЗрд╖ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ, рдпрд╣рд╛рдВ рд╣рдо ActivatorUtilities рдХреНрд▓рд╛рд╕ рдХреЗ рд╕реНрдерд┐рд░ рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред ActivatorUtilities.CreateInstance IServiceProvider рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ, рдмрдирд╛рдИ рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╡рд╕реНрддреБ рдХрд╛ рдкреНрд░рдХрд╛рд░ рдФрд░ рдирд┐рд░реНрднрд░рддрд╛ рдЙрджрд╛рд╣рд░рдг рд╣реИ рдХрд┐ рдпрд╣ рдСрдмреНрдЬреЗрдХреНрдЯ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ (рдЖрдк рдХреЗрд╡рд▓ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдкрдВрдЬреАрдХреГрдд рдирд╣реАрдВ рд╣реИрдВ, рдкреНрд░рджрд╛рддрд╛ рджреНрд╡рд╛рд░рд╛ рдЕрдиреБрдорддрд┐ рджреА рдЬрд╛рдПрдЧреА)


ActivatorUtilities.GetServiceOrCreateInstance - рд╡рд╣реА рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдмрдирд╛рдП рдЧрдП рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рд▓рд╛рдкрддрд╛ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рдпрджрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рд╣реИ, рддреЛ рдпрд╣ рдмрд╕ рдЗрд╕реЗ рдмрдирд╛рдПрдЧрд╛ (рдпрд╛ рдкрд╣рд▓реЗ рд╕реЗ рдмрдирд╛рдП рдЧрдП рдПрдХ рдХреЛ рд╡рд╛рдкрд╕ рд▓реМрдЯрд╛рдПрдЧрд╛), рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ, рдмрд╢рд░реНрддреЗ рдХрд┐ рдпрд╣ рдЕрдкрдиреА рд╕рднреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рд╣рд▓ рдХрд░ рд╕рдХреЗ


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЖрдк рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдХреИрд╢ рдСрдмреНрдЬреЗрдХреНрдЯ рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдФрд░ рд╕реЗрд╡рд╛рдУрдВ рдореЗрдВ рдЗрд╕ рдкрдВрдЬреАрдХрд░рдг рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рдбрд┐рд╕реНрдХреНрд░рд┐рдкреНрдЯрд░ рдЬреЛрдбрд╝рддрд╛ рд╣реИред


рдЖрдЗрдП рдПрдХ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗрдВ:


 public class DtoQuery : IQuery<Dto, Something> { private readonly IRepository _repository; public DtoQuery(IRepository repository) { _repository = repository; } public Something Query(Dto input) => _repository.GetSomething(); } //    private IQuery<Dto, Something> query { get; set; } public void TwoCallQueryTest() { var dto = new Dto {One = 1}; var dto1 = new Dto {One = 1}; //query -        query.Query(dto); query.Query(dto1); // : services.AddScoped<IRepository>(x => MockRepository.Object) RepositoryMock.Verify(x => x.GetSomething(), Times.Once); } 

ReposityMock - Moq рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ рдореЙрдХ рдордЬрд╝реЗрджрд╛рд░ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рдЧреЗрдЯрд╕реНрдореЛрдореЗрд▓ () рд╡рд┐рдзрд┐ рдХреЛ рдХрд┐рддрдиреА рдмрд╛рд░ рдХрд╣рд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╣ рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдХреИрд╕рд▓.рдЗрдВрдЯрд░рдореАрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдиреНрд╣реЗрдВ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИред рд╣рдо рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдХреЛрд░реЗрдЯрд░реНрд╕ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддреЗ рд╣реИрдВред

рдпрд╣ рд╣реИ рдХрд┐ рдЖрдк рд╕рднреА IQuery <TIn, TOut> рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рдХреИрд╢рд┐рдВрдЧ рдХреЛ рдХреИрд╕реЗ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рдереЛрдбрд╝рд╛ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрддрдирд╛ рдХреЛрдб рд▓рд┐рдЦрдирд╛ рдмрд╣реБрдд рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред


рдЕрдиреНрдп рдЙрдкрд╛рдп


MediatR


рдХреЗрдВрджреНрд░реАрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЗрдВрдЯрд░рдлрд╝реЗрд╕:


 public interface IRequestHandler<in TRequest, TResponse> where TRequest : IRequest<TResponse> { Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken); } 

MediatR рдХреА рдореБрдЦреНрдп рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдПрдХ IRequestHandler рдкрд░ рд░реИрдкрд░ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, IPipelineBehavior рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛, рдпрд╣ рд╣реИ рдХрд┐ рдЖрдк CachePipelineBehaviour рдХреЛ рдХреИрд╕реЗ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ рд╕рднреА рдкрдВрдЬреАрдХреГрдд IRequestHandler рдЗрдВрдЯрд░рдлреЗрд╕ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрдЧрд╛:


 sc.AddScoped(typeof(IPipelineBehavior<,>), typeof(CachePipelineBehaviour<,>)); 

рд╣рдо рдХреИрд╢рд┐рдВрдЧ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:


 public class CachePipelineBehaviour<TDto, TResult> : IPipelineBehavior<TDto, TResult> { private readonly ConcurrentDictionary<TDto, Task<TResult>> _cache; public CachePipelineBehaviour( IConcurrentDictionaryFactory<TDto, Task<TResult>> cacheFactory) { _cache = cacheFactory.Create(); } public async Task<TResult> Handle(TDto request, CancellationToken cancellationToken, RequestHandlerDelegate<TResult> next) => await _cache.GetOrAdd(request, x => next()); } 

рдЕрдиреБрд░реЛрдз рдХрд╛ Dto, рд░рджреНрдж рдХрд░рдиреЗ рдХрд╛ рдЯреЛрдХрди, рдФрд░ RequestHandlerDelegate рд╣реИрдВрдбрд▓ рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИред рдЙрддреНрддрд░рд╛рд░реНрджреНрдз рдЕрдиреНрдп рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдФрд░ рд╣реИрдВрдбрд▓рд░ рдХреА рдЕрдЧрд▓реА рдХреЙрд▓ рдкрд░ рд╕рд┐рд░реНрдл рдПрдХ рдЖрд╡рд░рдг рд╣реИред MediatR рдЕрд╕реЗрдВрдмрд▓реА рдХреЛ рд╕реНрдХреИрди рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╕рднреА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рддрд╛ рд╣реИред рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ IMediator рдХреЛ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдЙрд╕ рдкрд░ рднреЗрдЬреЗрдВ рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВ Dto рдЧреБрдЬрд░ рд░рд╣рд╛ рд╣реИ:


 public async Task<IActionResult>([FromBody] Dto dto){ return Ok(mediator.Send(dto)); } 

MediatR рд╕реНрд╡рдпрдВ рдЗрд╕реЗ рдвреВрдВрдвреЗрдЧрд╛, IRequestHabdler рдХрд╛ рдЙрдкрдпреБрдХреНрдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдвреВрдВрдвреЗрдЧрд╛ рдФрд░ рд╕рднреА рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдЧрд╛ (PipelineBehaviour рдХреЗ рдЕрд▓рд╛рд╡рд╛, IPreRequestHandler рдФрд░ IPostRequestHandler рднреА рд╣реИ)


рдорд╣рд▓ рдХреА рд╣рд╡рд╛


рдХрдВрдЯреЗрдирд░ рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛ рдЧрддрд┐рд╢реАрд▓ рдЖрд╡рд░рдг рдХреА рдкреАрдврд╝реА рд╣реИ, рдпрд╣ рдЧрддрд┐рд╢реАрд▓ рдПрдУрдкреА рд╣реИред


рдПрдВрдЯрд┐рдЯреА рдлреНрд░реЗрдорд╡рд░реНрдХ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЖрд▓рд╕реА рд▓реЛрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реИ, рд╕рдВрдкрддреНрддрд┐ рдкрд╛рдиреЗ рд╡рд╛рд▓реЗ рдореЗрдВ, ILazyLoader рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреА рд▓реЛрдб рд╡рд┐рдзрд┐ рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рднреА рд░реИрдкрд░реЛрдВ рдХреЗ рд╡рд░реНрдЧреЛрдВ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рд░реИрдкрд░ рдХреА рдкреАрдврд╝реА рдХреЗ рд╕рд╛рде рдХрдВрдЯреЗрдирд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░ рдмрдирд╛рдиреЗ рдФрд░ рдЗрд╕реЗ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ


  public class CacheInterceptor<TIn, TOut> : IInterceptor { private readonly ConcurrentDictionary<TIn, TOut> _cache; public CacheInterceptor( IConcurrentDictionaryFactory<TIn, TOut> cacheFactory) { _cache = cacheFactory.Create(); } public void Intercept(IInvocation invocation) { var input = (TIn) invocation.Arguments.Single(); if (_cache.TryGetValue(input, out var value)) invocation.ReturnValue = value; else { invocation.Proceed(); _cache.TryAdd(input, (TOut) invocation.ReturnValue); } } } 

IInvocation рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕рдЬрд╛рдпрд╛ рдЧрдпрд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╕рджрд╕реНрдп рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдПрдХреНрд╕реЗрд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рд╕рджрд╕реНрдп рдХреНрд╡реЗрд░реА рд╡рд┐рдзрд┐ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдпрд╣ рдЬрд╛рдВрдЪ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ рдХрд┐ рдПрдХреНрд╕реЗрд╕ рдЗрд╕реЗ рдкрдВрдЬреАрдХреГрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдХреЛрдИ рдЕрдиреНрдп рд╡рд┐рдХрд▓реНрдк рдирд╣реАрдВ рд╣реИрдВред


рдпрджрд┐ рдХреИрд╢ рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреА рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╡рд╕реНрддреБ рд╣реИ, рддреЛ рд╡рд┐рдзрд┐ рдХреЗ рд░рд┐рдЯрд░реНрди рдорд╛рди рдХреЛ рднрд░реЗрдВ (рдЗрд╕реЗ рдХреЙрд▓ рдХрд┐рдП рдмрд┐рдирд╛), рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдкреНрд░реЛрд╕рд┐рдб рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВ, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ, рд╕рдЬрд╛рдП рдЧрдП рддрд░реАрдХреЗ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ рдФрд░ рд░рд┐рдЯрд░реНрдирд╡реИрд▓реНрдпреВ рдореЗрдВ рднрд░реЗрдВред


Githab рдкрд░ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░ рдкрдВрдЬреАрдХрд░рдг рдФрд░ рдкреВрд░реНрдг рдХреЛрдб рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ

Source: https://habr.com/ru/post/hi449744/


All Articles