无论提供的类型如何,都从C#generic返回null

时间:2011-09-20 21:33:39

标签: c# generics

我正在为我们的网络服务编写内存缓存设置。这样我们就不必在每次需要设置时都访问数据库。我们有一种机制可以在更新数据库时使缓存失效。

缓存是一堆包含不同类型的字典,这里有两个字典:

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但不确定如何。

5 个答案:

答案 0 :(得分:6)

否 - 如果TValueint,那么就不能为空

这正是为什么Dictionary.TryGetValue(你应该在内部使用,而不是使用ContainsKey然后第二次查找)返回bool并拥有out的原因值本身的参数。

这样说:假设TValuebyte。您的方法可以返回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。