MemoryCache
внутренне использует ConcurrentDictionary<object, CacheEntry>
, который, в свою очередь, использует компаратор по умолчанию для типа object
, который выполняет сравнение на равенство на основе фактических переопределений типа Object.Equals
и * 1007. *. В вашем случае ваши ключи ValueTuple<string, Query>
, независимо от того, какой у вас класс Query
. ValueTuple<T1,T2>.Equals
оценивается как true, если компоненты сравниваемого экземпляра относятся к тем же типам, что и компоненты текущего экземпляра, и если компоненты равны компонентам текущего экземпляра, причем равенство определяется средство сравнения по умолчанию для каждого компонента.
Таким образом, то, как выполняется сравнение на равенство, зависит от реализации вашего Query
типа. Если этот тип не переопределяет Equals
и GetHashCode
, а также не реализует IEquatable<T>
, то выполняется равенство ссылок, то есть равенство достигается только при передаче в одном и том же экземпляре запроса. Если вы хотите изменить это поведение, вы должны расширить класс Query
для реализации IEquatable<Query>
.
Я также обнаружил, что CreateEntry
не сразу добавляет новую запись в кеш. Документация .NET Core неутешительно редка, поэтому я не нашел предполагаемого поведения; тем не менее, вы можете убедиться, что запись добавлена, вызвав Set
.
Пример:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Caching.Memory;
class Program
{
static void Main(string[] args)
{
var query1 = new Query { Parts = { new List<string> { "abc", "def", "ghi" } } };
var query2 = new Query { Parts = { new List<string> { "abc", "def", "ghi" } } };
var memoryCache = new MemoryCache(new MemoryCacheOptions());
memoryCache.Set(("typeOfCache", query1), new object());
var found = memoryCache.TryGetValue(("typeOfCache", query2), out var something);
Console.WriteLine(found);
}
public class Query : IEquatable<Query>
{
public List<List<string>> Parts { get; } = new List<List<string>>();
public bool Equals(Query other)
{
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(other, null)) return false;
return this.Parts.Length == other.Parts.Length
&& this.Parts.Zip(other.Parts, (x, y) => x.SequenceEqual(y)).All(b => b);
}
public override bool Equals(object obj)
{
return Equals(obj as Query);
}
public override int GetHashCode()
{
return this.Parts.SelectMany(p => p).Take(10).Aggregate(17, (acc, p) => acc * 23 + p?.GetHashCode() ?? 0);
}
}
}