Open sandboxFocusImprove this doc

LAMA5105: [InvalidateCache] doesn't name any method to invalidate

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.

Source Code
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
Transformed Code
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

See also