C#, сгенерируйте постоянный ключ для массива объекта
Я хотел бы сохранить в Cache объект с постоянным ключом.
public TItem Set<TItem>(string key, TItem value)
{
return = _memoryCache.Set(key, value);
}
Я получаю свой объект с помощью функции:
public TItem Get(
TPrimaryKey id,
params object[] args,
bool byPassCaching = false
)
{
if (byPassCaching || !_cacheManager.TryGetValue<TItem>(GetKey(id, args), out TItem result)){
item = [FUNCTION TO GET ITEM];
_cacheManager.Set(GetKey(id, args), item)
}
return item;
}
Я хотел бы сгенерировать постоянный ключ для TItem, Id (int) и некоторых параметров (object [] args).
Вот моя функция для генерации постоянного ключа:
internal static string GetKey<TItem>(int id, params object[] args)
{
return string.Format("{0}#{1}[{2}]", typeof(TItem).FullName, id, args?[FUNCTION TO CALL]);
}
[FUNCTION TO CALL] - это функция, которую я ищу.
Поэтому в следующий раз, когда я вызову функцию с тем же параметром, у меня будет тот же ключ.
Например
GetKey<MyClass>(1, null) => "MyApp.MyClass#1[]"
GetKey<MyClass>(1, "Hello", "World") => "MyApp.MyClass#1[sdas5d1as5d4sd8]"
GetKey<MyClass>(1, "Hello", "World") => "MyApp.MyClass#1[sdas5d1as5d4sd8]"
GetKey<MyClass>(1, item => item.Include(s => s.Categories)) => "MyApp.MyClass#1[asdasdasd87wqw]"
В начале я думал использовать GetHashCode, но генерируемый int всегда отличается.
Как я могу это сделать?
1 ответ
Я думаю, GetHashCode - это то, что вам нужно; Вы вызывали GetHashCode для массива или вызывали его для каждого члена массива? Вы хотите сделать последнее.
Следующее должно быть похоже на то, что вы хотите; если params равен нулю или пуст, или полон пустых объектов, то код будет 00000000.
В противном случае, если параметры совпадают, результирующий хеш будет таким же. И если параметры имеют другой порядок или другие значения, то хеш будет другим.
internal static string GetKey<TEntity>(int id, params object[] args)
{
return string.Format("{0}#{1}[{2}]", typeof(TEntity).FullName, id, ArrayHash(args));
}
static string ArrayHash(params object[] values)
{
return BitConverter.ToString(BitConverter.GetBytes(ArrayHashCode(values))).Replace("-", "").ToLowerInvariant();
}
static int ArrayHashCode(params object[] values)
{
if (values == null || values.Length == 0) return 0;
var value = values[0];
int hashCode = value == null ? 0 : value.GetHashCode();
for (int i = 1; i < values.Length; i++)
{
value = values[i];
unchecked
{
hashCode = (hashCode * 397) ^ (value == null ? 0 : value.GetHashCode());
}
}
return hashCode;
}
Обратите внимание, что 397 - это простое число, которое я выбрал из реализации GetShashCode в ReSharper, что позволяет красиво распределять хэш-коды через переполнение (изящно разрешенное для блока без контроля).
Пример хешированных параметров будет выглядеть так:
ArrayHash( 1, null, "test" ) => "dee9e1ea"
ArrayHash( 1, null, "test" ) => "dee9e1ea"
ArrayHash( null, 1, "test" ) => "fa8fe3ea"
ArrayHash("one", "two", "three") => "8841b2be"
ArrayHash() => "00000000"
ArrayHash(null) => "00000000"
ArrayHash(new object[] {}) => "00000000"
Обратите внимание, что если массив params содержит объекты, они также должны иметь правильную реализацию GetHashCode.