2011-09-20 83 views
0

我正在为我们的webservices编写内存缓存设置。这样我们就不需要每次需要设置时都需要访问数据库。我们有一种机制在数据库更新时使缓存失效。无论提供哪种类型,都从C#泛型返回null

缓存是一串包含不同类型的词典,这里的这些字典中的两种:

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’,因为它可能是一个非空的值类型考虑使用'而不是“默认(TValue)”。“

我想返回null而不是默认值(TValue)的原因是,在整数情况下,调用方无法知道设置值实际上是0还是它在缓存中找不到。

所以我的问题是,是否有限制,我可以把一个泛型,将允许我返回null,无论提供的类型? (我假设我需要使用可空,但不知道如何

+0

与您的特定问题无关,但您可能会考虑使用'ReadWriterLock'(或者更好的是'ReaderWriterLockSlim'),因为多个读者可能没有理由互相阻止。 – dlev

回答

2

除@Jon Skeet的回答是,您可以通过返回bool来重写您的方法,使其类似于Dictionary.TryGetValue,并将结果作为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

6

不 - 。如果TValueint那么它根本不能为空

这正是为什么Dictionary.TryGetValue(这是你应该在内部使用,而不是使用ContainsKey再进行第二次查询)返回bool并具有价值本身out参数

这样说吧:假设TValuebyte有256个可能的值,你的方法可能会返回。 - 但是有257个可能的结果:高速缓存中的256个可能的字节值,以及未找到的可能性。

0

由于乔恩写道TValue的VAR不能为空 但你真的可以使用可空,并宣布通用为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; 
} 
+0

使用此方法,您只能在字典中存储值类型。 'String'是不可能的,因为没有'String?'这样的东西。 –

0

您可以添加“,其中TValue:类“在函数签名的末尾,以便确保TValue是引用类型,那么您可以使用null。

+0

Int64不是类类型,它是一个结构类型。 – MatteKarla

+0

使用这种方法,你只能在字典中存储引用类型。但是,'Int64'是一个值类型。 –

1

使用空Int64的,那么你可以使用默认值(TValue)

static readonly Dictionary<string, Dictionary<string, Int64?>> IntegerValueCache 
    = new Dictionary<string, Dictionary<string, Int64?>>(); 

但试图缓存Web服务数据时,你不应该使用静态变量,使用 HttpContext.Current.Cache代替