我正在为我们的网络服务编写内存缓存设置。这样我们就不必在每次需要设置时都访问数据库。我们有一种机制可以在更新数据库时使缓存失效。
缓存是一堆包含不同类型的字典,这里有两个字典:
static readonly object StringValueCacheMutex = new object();
static readonly Dictionary<string, Dictionary<string, string>> StringValueCache = new Dictionary<string, Dictionary<string, string>>();
static readonly object IntegerValueCacheMutex = new object();
static readonly Dictionary<string, Dictionary<string, Int64>> IntegerValueCache = new Dictionary<string, Dictionary<string, Int64>>();
我想编写一个从这些字典中获取值的泛型函数,如果在字典中找不到类别/设置,它应返回null以表示未找到它。
问题是这些词典包含可空和非可空类型。
这是我想要的通用:
public static TValue GetValueOrNull<TValue>(
IDictionary<string, Dictionary<string, TValue>> cacheDictionary,
object cacheMutex,
string categoryName,
string settingName)
{
TValue value = null;
lock (cacheMutex)
{
if (cacheDictionary.ContainsKey(categoryName))
{
if (cacheDictionary[categoryName].ContainsKey(settingName))
{
value = cacheDictionary[categoryName][settingName];
}
}
}
return value;
}
由于以下原因无法编译:“无法将null转换为类型参数'TValue',因为它可能是一个不可为空的值类型。请考虑使用'default(TValue)'。”
我想返回null而不是默认值(TValue)的原因是,在整数的情况下,调用者无法知道设置值是否实际为0或者是否在缓存中找不到它。 / p>
所以我的问题是,是否存在我可以放在一个泛型上的约束,它允许我返回null而不管提供的类型是什么? (我假设我需要使用Nullable但不确定如何。
答案 0 :(得分:6)
否 - 如果TValue
为int
,那么就不能为空。
这正是为什么Dictionary.TryGetValue
(你应该在内部使用,而不是使用ContainsKey
然后第二次查找)返回bool
并拥有out
的原因值本身的参数。
这样说:假设TValue
是byte
。您的方法可以返回256个可能的值 - 但是有257种可能的结果:缓存中的256个可能的字节值,以及未找到它的可能性。
答案 1 :(得分:2)
除了@Jon Skeet的答案之外,您可以通过返回Dictionary.TryGetValue
并将结果作为bool
参数重写您的方法,使其类似于out
。您无需使用Nullable<T>
。
public static bool GetValueOrNull<TValue>(
IDictionary<string, Dictionary<string, TValue>> cacheDictionary,
object cacheMutex,
string categoryName,
string settingName,
out TValue value)
{
lock (cacheMutex) {
Dictionary<string, TValue> category;
if (cacheDictionary.TryGetValue(categoryName, out category)) {
if (category.TryGetValue(settingName, out value))
return true; // setting was found
}
}
value = default(TValue);
return false; // setting was not found
}
我还会将方法名称重写为TryGetValue
。
答案 2 :(得分:1)
使用可以为空的Int64,然后您可以使用默认(TValue)
static readonly Dictionary<string, Dictionary<string, Int64?>> IntegerValueCache
= new Dictionary<string, Dictionary<string, Int64?>>();
但是当尝试缓存Web服务数据时,不应使用静态变量,请使用 而是HttpContext.Current.Cache
答案 3 :(得分:0)
正如乔恩所写的那样,TValue不能为空
但你真的可以使用nullable并将泛型声明为G<T?> where T : struct
所以你的代码将是
public static TValue? GetValueOrNull<TValue?>(
IDictionary<string, Dictionary<string, TValue>> cacheDictionary,
object cacheMutex,
string categoryName,
string settingName)
{
TValue? value = null;
lock (cacheMutex)
{
if (cacheDictionary.ContainsKey(categoryName))
{
if (cacheDictionary[categoryName].ContainsKey(settingName))
{
value = cacheDictionary[categoryName][settingName];
}
}
}
return value;
}
答案 4 :(得分:0)
您可以在函数签名的末尾添加“where TValue:class”,以便确保TValue是引用类型,然后您可以使用null。