| Severity | Error |
| Reported by | Metalama.Patterns.Caching |
| Message | Invalid [InvalidateCache] aspect on '<InvalidatingMethod>': there are several suitable overloads of the '<MethodName>' method. Set the AllowMultipleOverloads property to true to invalidate all of them. |
Cause
The [InvalidateCache] aspect identifies the cached methods by name only. When several overloads have this name, the aspect considers an overload suitable if it's cached and if each of its parameters, except those marked with [NotCacheKey], matches a parameter of the invalidating method by name and type.
To prevent you from invalidating more methods than you intended, Metalama reports LAMA5107 when more than one overload is suitable and the AllowMultipleOverloads property isn't set to true. In the message, <InvalidatingMethod> is the invalidating method and <MethodName> is the name of the overloaded method.
In the following example, both overloads of GetProducts are cached, and the parameters of both can be matched with the parameters of AddProduct.
1using Metalama.Patterns.Caching.Aspects;
2using System.Collections.Generic;
3using System.Linq;
4
5namespace Doc.LAMA5107.Error;
6
7public sealed partial class ProductCatalogue
8{
9 // Maps product identifiers to categories.
10 private readonly Dictionary<string, string> _categories = new() { ["corn"] = "cereals" };
11
12 [Cache]
13 public string[] GetProducts() => this._categories.Keys.ToArray();
14
15 [Cache]
16 public string[] GetProducts( string category )
17 => this._categories.Where( p => p.Value == category ).Select( p => p.Key ).ToArray();
18
19 // Error: both overloads of GetProducts can be invalidated by this method.
20 [InvalidateCache( nameof(GetProducts) )]
Error LAMA5107: Invalid [InvalidateCache] aspect on 'ProductCatalogue.AddProduct(string, string)': there are several suitable overloads of the 'GetProducts' method. Set the AllowMultipleOverloads property to true to invalidate all of them.
21 public void AddProduct( string productId, string category ) => this._categories.Add( productId, category );
22}
23
Resolution
- If you want to invalidate all suitable overloads, set the AllowMultipleOverloads property to
true, as in the following example. - If you want to invalidate only one overload, rename the cached methods so that each of them has a distinct name, and pass the name of the method you want to invalidate.
1using Metalama.Patterns.Caching.Aspects;
2using System.Collections.Generic;
3using System.Linq;
4
5namespace Doc.LAMA5107.Fixed;
6
7public sealed partial class ProductCatalogue
8{
9 // Maps product identifiers to categories.
10 private readonly Dictionary<string, string> _categories = new() { ["corn"] = "cereals" };
11
12 [Cache]
13 public string[] GetProducts() => this._categories.Keys.ToArray();
14
15 [Cache]
16 public string[] GetProducts( string category )
17 => this._categories.Where( p => p.Value == category ).Select( p => p.Key ).ToArray();
18
19 // Fixed: the aspect explicitly invalidates all overloads of GetProducts.
20 [InvalidateCache( nameof(GetProducts), AllowMultipleOverloads = true )]
21 public void AddProduct( string productId, string category ) => this._categories.Add( productId, category );
22}
23
1using Metalama.Patterns.Caching;
2using Metalama.Patterns.Caching.Aspects;
3using System;
4using System.Collections.Generic;
5using System.Linq;
6using System.Reflection;
7
8namespace Doc.LAMA5107.Fixed;
9
10public sealed partial class ProductCatalogue
11{
12 // Maps product identifiers to categories.
13 private readonly Dictionary<string, string> _categories = new() { ["corn"] = "cereals" };
14
15 [Cache]
16 public string[] GetProducts()
17 {
18 static object? Invoke(object? instance, object?[] args)
19 {
20 return ((ProductCatalogue)instance).GetProducts_Source();
21 }
22
23 return _cachingService.GetFromCacheOrExecute<string[]>(_cacheRegistration_GetProducts, this, new object[] { }, Invoke);
24 }
25
26 private string[] GetProducts_Source() => this._categories.Keys.ToArray();
27
28 [Cache]
29 public string[] GetProducts(string category)
30
31 {
32 static object? Invoke(object? instance, object?[] args)
33 {
34 return ((ProductCatalogue)instance).GetProducts_Source((string)args[0]);
35 }
36
37 return _cachingService.GetFromCacheOrExecute<string[]>(_cacheRegistration_GetProducts2, this, new object[] { category }, Invoke);
38 }
39
40 private string[] GetProducts_Source(string category) => this._categories.Where(p => p.Value == category).Select(p => p.Key).ToArray();
41
42 // Fixed: the aspect explicitly invalidates all overloads of GetProducts.
43 [InvalidateCache(nameof(GetProducts), AllowMultipleOverloads = true)]
44 public void AddProduct(string productId, string category)
45 {
46 this._categories.Add(productId, category);
47 object result = null;
48 _cachingService.Invalidate(_methodsInvalidatedBy_AddProduct_7D5E6CC336575F72EE1795F60AC63FA8[0], this, new object[] { });
49 _cachingService.Invalidate(_methodsInvalidatedBy_AddProduct_7D5E6CC336575F72EE1795F60AC63FA8[1], this, new object[] { category });
50 }
51
52 private static readonly CachedMethodMetadata _cacheRegistration_GetProducts;
53 private static readonly CachedMethodMetadata _cacheRegistration_GetProducts2;
54 private ICachingService _cachingService;
55 private static MethodInfo[] _methodsInvalidatedBy_AddProduct_7D5E6CC336575F72EE1795F60AC63FA8;
56
57 static ProductCatalogue()
58 {
59 _methodsInvalidatedBy_AddProduct_7D5E6CC336575F72EE1795F60AC63FA8 = new MethodInfo[] {
60 typeof(ProductCatalogue).GetMethod("GetProducts", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null) ?? throw new MissingMethodException("The method 'ProductCatalogue.GetProducts()' could not be found using reflection."),
61 typeof(ProductCatalogue).GetMethod("GetProducts", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string) }, null) ?? throw new MissingMethodException("The method 'ProductCatalogue.GetProducts(string)' could not be found using reflection.")
62 };
63 _cacheRegistration_GetProducts2 = CachedMethodMetadata.Register(typeof(ProductCatalogue).GetMethod("GetProducts", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string) }, null) ?? throw new MissingMethodException("The method 'ProductCatalogue.GetProducts(string)' could not be found using reflection."), new CachedMethodConfiguration() { AbsoluteExpiration = null, AutoReload = null, IgnoreThisParameter = null, Priority = null, ProfileName = (string?)null, SlidingExpiration = null }, true);
64 _cacheRegistration_GetProducts = CachedMethodMetadata.Register(typeof(ProductCatalogue).GetMethod("GetProducts", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null) ?? throw new MissingMethodException("The method 'ProductCatalogue.GetProducts()' could not be found using reflection."), new CachedMethodConfiguration() { AbsoluteExpiration = null, AutoReload = null, IgnoreThisParameter = null, Priority = null, ProfileName = (string?)null, SlidingExpiration = null }, true);
65 }
66
67 public ProductCatalogue(ICachingService? cachingService = null)
68 {
69 this._cachingService = cachingService ?? throw new System.ArgumentNullException(nameof(cachingService));
70 }
71}
72