Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何通过键访问字典值来获取null而不是KeyNotFoundException?_C#_Dictionary - Fatal编程技术网

C# 如何通过键访问字典值来获取null而不是KeyNotFoundException?

C# 如何通过键访问字典值来获取null而不是KeyNotFoundException?,c#,dictionary,C#,Dictionary,在某些特定的场景中,当字典中没有这样的键时,在通过键访问字典值时,使用一种简短、可读的方式获取null而不是KeyNotFoundException,似乎对我很有用 我首先想到的是一种扩展方法: public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key) where U : class //it's acceptable for me to have this c

在某些特定的场景中,当字典中没有这样的键时,在通过键访问字典值时,使用一种简短、可读的方式获取
null
而不是
KeyNotFoundException
,似乎对我很有用

我首先想到的是一种扩展方法:

public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key)
        where U : class //it's acceptable for me to have this constraint
{
    if (dict.ContainsKey(key))
        return dict[key];
    else 
        //it could be default(U) to use without U class constraint
        //however, I didn't need this.
        return null; 
}
我想说,最好有一些接近基本语法的东西:
dict[“key4”]

然后我想出了一个主意,让一个类有一个
private
字典字段,它公开了我需要的功能:

public class MyDictionary<T, U> //here I may add any of interfaces, implemented
                                //by dictionary itself to get an opportunity to,
                                //say, use foreach, etc. and implement them
                                // using the dictionary field.
        where U : class
{
    private Dictionary<T, U> dict;

    public MyDictionary()
    {
        dict = new Dictionary<T, U>();
    }

    public U this[T key]
    {
        get
        {
            if (dict.ContainsKey(key))
                return dict[key];
            else
                return null;
        }
        set
        {
            dict[key] = value;
        }
    }
}
因此它可以像
GetDictValueByKeyOrNull(“key1”)
那样使用


请你再给我一些建议或者帮我选择一个更好的好吗?

我说我不会使用这个。
new
关键字虽然在这种情况下很有用,但会产生很难找到的bug。除此之外,你可以试试这门课

class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            return TryGetValue(key, out value) ? value : default(TValue);
        }
        set { base[key] = value; }
    }
}
classmydictionary:Dictionary
{
公共新TValue此[TKey]
{
得到
{
t价值;
返回TryGetValue(键,输出值)?值:默认值(TValue);
}
set{base[key]=value;}
}
}

最后,我提出了一个变体,它使用了一个派生自dictionary类的显式接口实现:

public interface INullValueDictionary<T, U>
    where U : class
{
    U this[T key] { get; }
}

public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
    where U : class
{
    U INullValueDictionary<T, U>.this[T key]
    {
        get
        {
            U val;
            this.TryGetValue(key, out val);
            return val;
        }
    }
}
INullValueDictionary中的公共接口
你在哪里上课
{
U这个[T键]{get;}
}
公共类NullValueDictionary:Dictionary,INullValueDictionary
你在哪里上课
{
U INullValueDictionary。此[T键]
{
得到
{
乌瓦尔;
此.TryGetValue(键,输出值);
返回val;
}
}
}
因此,它通过以下方式公开了我需要的功能:

//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
    {1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;

try
{
    //this throws an exception, as the base class implementation is utilized
    Console.WriteLine(dict[2] ?? "null");
}
catch { }
//this prints null, as the explicit interface implementation 
//in the derived class is used
Console.WriteLine(idict[2] ?? "null");
//创建一些字典
NullValueDictionary dict=新的NullValueDictionary
{
{1,“一”}
};
//有对接口的引用
INullValueDictionary idict=dict;
尝试
{
//当使用基类实现时,这会引发异常
控制台写入线(dict[2]??“null”);
}
捕获{}
//这将输出null,作为显式接口实现
//在派生类中使用
控制台写入线(idict[2]??“null”);

使用扩展方法无法获得所需的语法,正如其他人所说,覆盖方法/运算符以更改其行为通常不是一个好主意。我想你能做的就是缩短你的名字

如果您需要继续使用IDictionary接口,就需要这样做。如果您没有与任何需要IDictionary的代码交互,那么您可以自由定义自己的接口,让[]操作符以不同的方式工作并不是问题

无论最终调用该函数的是什么,您都希望实现它,如下所示:

string.Format("{0}:{1};{2}:{3}",                                                 
              dict.GetValueByKeyOrNull("key1"),
              dict.GetValueByKeyOrNull("key2"),
              dict.GetValueByKeyOrNull("key3"),
              dict.GetValueByKeyOrNull("key4"));
Func<string, string> GetDictValueByKeyOrNull = (key) =>
{
    if (dict.ContainsKey(key))
        return dict[key];
    else
        return null;
};
public static U Get<T, U>(this Dictionary<T, U> dict, T key)
    where U : class
{
    U val;
    dict.TryGetValue(key, out val);
    return val;
}
publicstaticu-Get(此字典dict dict,T键)
你在哪里上课
{
乌瓦尔;
dict.TryGetValue(键,输出值);
返回val;
}

它只执行一次查找,而您的实现只有2次查找。

值得指出的是,默认情况下会执行此操作。 您将丢失泛型类型,但如果找不到功能,将获得null


而且(至少在理论上)我认为,您可以在较低的值数量下获得性能优势。

这是我个人库中的解决方案,作为扩展方法实现。我之所以发布它,是因为它是从dictionary接口实现的,并允许传入可选的默认值

实施

public static TV GetValue<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue = default(TV))
{
    TV value;
    return dict.TryGetValue(key, out value) ? value : defaultValue;
}

我以前做过这项工作,只继承常规Dictionary类并隐藏索引器效果很好。这样做非常简单,因此您可以自动获得常规Dictionary类的所有可靠性和熟悉性

public class NullSafeDict<TKey, TValue> : Dictionary<TKey, TValue> where TValue : class
{
    public new TValue this[TKey key]
    {
        get
        {
            if (!ContainsKey(key))
                return null;
            else
                return base[key];
        }
        set
        {
            if (!ContainsKey(key))
                Add(key, value);
            else
                base[key] = value;
        }
    }
}
公共类nulsafedict:Dictionary,其中TValue:class
{
公共新TValue此[TKey]
{
得到
{
如果(!ContainsKey(键))
返回null;
其他的
返回基[键];
}
设置
{
如果(!ContainsKey(键))
添加(键、值);
其他的
基[键]=值;
}
}
}

添加一个
字典扩展类

public static class DictionaryExtension
{
    public static TValue GetValueOrDefault<TKey, TValue>
        (   this IDictionary<TKey, TValue> dictionary,TKey key)
    {
        TValue value;
        return dictionary.TryGetValue(key, out value) ? value : default(TValue);
    }
}

这不会短得多,但是假设该值可以为null,那么
查找不会引发异常-
查找[key]。FirstOrDefault()
@SimonMcKenzie谢谢,我会想到它相关的:也许这是新的,但我们为什么不直接使用
dict.TryGetValue
@杰西,说话不像我想的那么简短是的,这违反了法律,由此产生的虫子真的很讨厌。@HonzaBrestan,你能解释一下吗?Thanks@arao6这将改变
字典
类的约定。您将获得一个默认值,而不是异常。这意味着,当某个键丢失时,现在可能会发生空引用异常,并且您无法判断该键何时丢失以及何时存在,但包含空值。考虑一个第三方方法,它接受一个<代码>字典<代码>,取决于它的行为,但是你提供了<代码> MyDealth> <代码>,而这个新的、冲突的行为。LSP说,无论在哪里使用基类,子类都应该是安全的(正确的)。这显然是由于契约的变化而导致的。@arao6看待这一点的另一种方式是通过类型系统——认为异常是方法签名(返回类型的扩展)的一部分,行为“在缺少键时抛出异常”(C#类型系统当然不能表达这一点,但我们现在可以认为它可以)。那么这个新的
MyDictionary
索引器的返回类型将与基类中的原始索引器的返回类型不同——这可能不是创建子类时需要的返回类型。哦,我现在明白了。再次感谢这实际上并没有回答这个问题。不过,感谢您提供的信息应该是
dict.TryGetValue
@IgorPas
public static class DictionaryExtension
{
    public static TValue GetValueOrDefault<TKey, TValue>
        (   this IDictionary<TKey, TValue> dictionary,TKey key)
    {
        TValue value;
        return dictionary.TryGetValue(key, out value) ? value : default(TValue);
    }
}
_dic.GetValueOrDefault();