为多个参数创建唯一键(缓存键)
Creating a unique key (cache key) for multiple parameters
我有一个基于 3 个参数缓存数据的方法。例如:
- 状态
- 年龄
- 兄弟姐妹人数。
现在我的系统中有很多排列,它们保存在字典中:
Dictionary<string,MyObject> cache;
字典的键是三者的组合,用 string.format
完成(像这样):
public string CreateKey(eState state, int age, int numberOfSibilings)
{
return string.format("{0}#{1}#{2}", state.ToString(), age.ToString(), numberOfSibilings.ToString());
}
eState
是一个 enum(int)
.
CreateKey
方法被调用了很多次并且是一个性能障碍,因为 string.format
不是特别快并且创建大量不可变字符串并不是最好的做法。
密钥可以包含用 *
替换的空条目。 CreateKey
方法在输入可空值时处理它们并检查它们是否具有值。
我相信有更好的方法来做到这一点。由于 eState
是 int
,我考虑过使用数学公式以更快的方式创建密钥,但我想不出快速且独特的方法。
无论如何,我愿意接受您可以提供的任何解决方案,以尽可能快速和内存友好地创建唯一密钥。
当代码对性能至关重要时,string.format
并不是那么好。它采用 Object
类型的参数,这意味着您需要将 int
和其他值类型装箱。
您可以创建一个自定义结构,用作字典的键。您需要在您的结构中实现 IEquatable<MyKey>
以便在调用 Equals
方法时不需要装箱。
public struct MyKey : IEquatable<MyKey>
{
public readonly eState State;
public readonly int Age;
public readonly int NumberOfSibilings;
...Implement Equals method here
}
然后使用
Dictionary<MyKey ,MyObject> cache;
public MyKey CreateKey(eState state, int age, int numberOfSibilings)
{
return new MyKey(state, age, numberOfSibilings);
}
这样您就不必在 CreateKey
方法中创建很多字符串。没有转换;您只需将它们存储为 int 并枚举本身。没有调用涉及拳击的 Enum.ToString
(我猜)。使用我们的 MyKey
结构,没有任何装箱。这意味着更好的性能。
如果您正在寻找调试器友好的密钥(在评论中提到),您可以使用 DebuggerDisplay
属性。
[DebuggerDisplay("State= {State} Age= {Age}")]
public struct MyKey : IEquatable<MyKey>
您也可以使用元组作为密钥:
Dictionary<Tuple<eState, int, int>, MyObject> dict;
元组像这样计算相等性:
- 它是一个
Tuple<T1, T2, T3>
对象
- 它的三个组成部分与被比较的元组类型相同
- 使用默认
Equals
方法,每个值都相等。
见https://msdn.microsoft.com/en-us/library/dd387109(v=vs.110).aspx
优点是您不必创建新类型来保存密钥,它对元组中的任何类型都使用相等比较器,并且易于使用:
var myKey = new Tuple<eState, int, int>(eState.Whatever, 10, 15);
dict.Add(myKey, myObject)
我有一个基于 3 个参数缓存数据的方法。例如:
- 状态
- 年龄
- 兄弟姐妹人数。
现在我的系统中有很多排列,它们保存在字典中:
Dictionary<string,MyObject> cache;
字典的键是三者的组合,用 string.format
完成(像这样):
public string CreateKey(eState state, int age, int numberOfSibilings)
{
return string.format("{0}#{1}#{2}", state.ToString(), age.ToString(), numberOfSibilings.ToString());
}
eState
是一个 enum(int)
.
CreateKey
方法被调用了很多次并且是一个性能障碍,因为 string.format
不是特别快并且创建大量不可变字符串并不是最好的做法。
密钥可以包含用 *
替换的空条目。 CreateKey
方法在输入可空值时处理它们并检查它们是否具有值。
我相信有更好的方法来做到这一点。由于 eState
是 int
,我考虑过使用数学公式以更快的方式创建密钥,但我想不出快速且独特的方法。
无论如何,我愿意接受您可以提供的任何解决方案,以尽可能快速和内存友好地创建唯一密钥。
string.format
并不是那么好。它采用 Object
类型的参数,这意味着您需要将 int
和其他值类型装箱。
您可以创建一个自定义结构,用作字典的键。您需要在您的结构中实现 IEquatable<MyKey>
以便在调用 Equals
方法时不需要装箱。
public struct MyKey : IEquatable<MyKey>
{
public readonly eState State;
public readonly int Age;
public readonly int NumberOfSibilings;
...Implement Equals method here
}
然后使用
Dictionary<MyKey ,MyObject> cache;
public MyKey CreateKey(eState state, int age, int numberOfSibilings)
{
return new MyKey(state, age, numberOfSibilings);
}
这样您就不必在 CreateKey
方法中创建很多字符串。没有转换;您只需将它们存储为 int 并枚举本身。没有调用涉及拳击的 Enum.ToString
(我猜)。使用我们的 MyKey
结构,没有任何装箱。这意味着更好的性能。
如果您正在寻找调试器友好的密钥(在评论中提到),您可以使用 DebuggerDisplay
属性。
[DebuggerDisplay("State= {State} Age= {Age}")]
public struct MyKey : IEquatable<MyKey>
您也可以使用元组作为密钥:
Dictionary<Tuple<eState, int, int>, MyObject> dict;
元组像这样计算相等性:
- 它是一个
Tuple<T1, T2, T3>
对象 - 它的三个组成部分与被比较的元组类型相同
- 使用默认
Equals
方法,每个值都相等。
见https://msdn.microsoft.com/en-us/library/dd387109(v=vs.110).aspx
优点是您不必创建新类型来保存密钥,它对元组中的任何类型都使用相等比较器,并且易于使用:
var myKey = new Tuple<eState, int, int>(eState.Whatever, 10, 15);
dict.Add(myKey, myObject)