| Severity | Error |
| Reported by | Metalama.Patterns.Caching |
| Message | Invalid [InvalidateCache] aspect on '<Method>': the constructor parameters must contain at least one method name. |
Cause
The [InvalidateCache] aspect removes from the cache the results of the cached methods whose names you pass to its constructor. Because the method names are a params array, C# accepts the attribute without any argument, or with only a type argument, but then the aspect has nothing to invalidate.
Metalama reports LAMA5105 when the list of method names is empty or null. The <Method> placeholder is the invalidating method, that is, the method to which the aspect is applied.
In the following example, the aspect is applied without any method name.
1using Metalama.Patterns.Caching.Aspects;
2using System.Collections.Generic;
3
4namespace Doc.LAMA5105.Error;
5
6public sealed partial class ProductCatalogue
7{
8 private readonly Dictionary<string, decimal> _prices = new() { ["corn"] = 100 };
9
10 [Cache]
11 public decimal GetPrice( string productId ) => this._prices[productId];
12
13 // Error: the aspect doesn't name any method to invalidate.
14 [InvalidateCache]
Error LAMA5105: Invalid [InvalidateCache] aspect on 'ProductCatalogue.UpdatePrice(string, decimal)': the constructor parameters must contain at least one method name.
15 public void UpdatePrice( string productId, decimal price ) => this._prices[productId] = price;
16}
17
Resolution
Pass the names of the cached methods to invalidate, preferably with the nameof operator. If the cached methods belong to a different type, pass this type as the first argument, followed by the method names.
1using Metalama.Patterns.Caching.Aspects;
2using System.Collections.Generic;
3
4namespace Doc.LAMA5105.Fixed;
5
6public sealed partial class ProductCatalogue
7{
8 private readonly Dictionary<string, decimal> _prices = new() { ["corn"] = 100 };
9
10 [Cache]
11 public decimal GetPrice( string productId ) => this._prices[productId];
12
13 // Fixed: the aspect names the cached method to invalidate.
14 [InvalidateCache( nameof(GetPrice) )]
15 public void UpdatePrice( string productId, decimal price ) => this._prices[productId] = price;
16}
17
1using Metalama.Patterns.Caching;
2using Metalama.Patterns.Caching.Aspects;
3using System;
4using System.Collections.Generic;
5using System.Reflection;
6
7namespace Doc.LAMA5105.Fixed;
8
9public sealed partial class ProductCatalogue
10{
11 private readonly Dictionary<string, decimal> _prices = new() { ["corn"] = 100 };
12
13 [Cache]
14 public decimal GetPrice(string productId)
15 {
16 static object? Invoke(object? instance, object?[] args)
17 {
18 return ((ProductCatalogue)instance).GetPrice_Source((string)args[0]);
19 }
20
21 return _cachingService.GetFromCacheOrExecute<decimal>(_cacheRegistration_GetPrice, this, new object[] { productId }, Invoke);
22 }
23
24 private decimal GetPrice_Source(string productId) => this._prices[productId];
25
26 // Fixed: the aspect names the cached method to invalidate.
27 [InvalidateCache(nameof(GetPrice))]
28 public void UpdatePrice(string productId, decimal price)
29 {
30 this._prices[productId] = price;
31 object result = null;
32 _cachingService.Invalidate(_methodsInvalidatedBy_UpdatePrice_E8490F7951990F2BE333D25A076527A0[0], this, new object[] { productId });
33 }
34
35 private static readonly CachedMethodMetadata _cacheRegistration_GetPrice;
36 private ICachingService _cachingService;
37 private static MethodInfo[] _methodsInvalidatedBy_UpdatePrice_E8490F7951990F2BE333D25A076527A0;
38
39 static ProductCatalogue()
40 {
41 _methodsInvalidatedBy_UpdatePrice_E8490F7951990F2BE333D25A076527A0 = new MethodInfo[] {
42 typeof(ProductCatalogue).GetMethod("GetPrice", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string) }, null) ?? throw new MissingMethodException("The method 'ProductCatalogue.GetPrice(string)' could not be found using reflection.")
43 };
44 _cacheRegistration_GetPrice = CachedMethodMetadata.Register(typeof(ProductCatalogue).GetMethod("GetPrice", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string) }, null) ?? throw new MissingMethodException("The method 'ProductCatalogue.GetPrice(string)' could not be found using reflection."), new CachedMethodConfiguration() { AbsoluteExpiration = null, AutoReload = null, IgnoreThisParameter = null, Priority = null, ProfileName = (string?)null, SlidingExpiration = null }, false);
45 }
46
47 public ProductCatalogue(ICachingService? cachingService = null)
48 {
49 this._cachingService = cachingService ?? throw new System.ArgumentNullException(nameof(cachingService));
50 }
51}
52