如果键不存在,字典返回默认值

发布于 2024-08-28 12:15:47 字数 759 浏览 5 评论 0原文

我发现自己现在在代码中经常使用当前模式,

var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

var somethingElse = dictionary.ContainsKey(key) ? dictionary[key] : new List<othertype>();
// Do work with the somethingelse variable

或者有时

var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

IList<othertype> somethingElse;
if(!dictionary.TryGetValue(key, out somethingElse) {
    somethingElse = new List<othertype>();
}

这两种方式都感觉很迂回。我真正想要的是像

dictionary.GetValueOrDefault(key)

现在,我可以为字典类编写一个扩展方法来为我做这件事,但我认为我可能会丢失一些已经存在的东西。那么,有没有一种方法可以在不编写字典扩展方法的情况下以更“眼睛容易”的方式做到这一点?

I find myself using the current pattern quite often in my code nowadays

var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

var somethingElse = dictionary.ContainsKey(key) ? dictionary[key] : new List<othertype>();
// Do work with the somethingelse variable

Or sometimes

var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

IList<othertype> somethingElse;
if(!dictionary.TryGetValue(key, out somethingElse) {
    somethingElse = new List<othertype>();
}

Both of these ways feel quite roundabout. What I really would like is something like

dictionary.GetValueOrDefault(key)

Now, I could write an extension method for the dictionary class that does this for me, but I figured that I might be missing something that already exists. SO, is there a way to do this in a way that is more "easy on the eyes" without writing an extension method to dictionary?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心房的律动 2024-09-04 12:15:47

根据评论,在 .Net Core 2+ / NetStandard 2.1+ / Net 5 中, MS 添加了扩展方法 GetValueOrDefault()


TryGetValue 已经将类型的默认值分配给字典,因此您可以use:

dictionary.TryGetValue(key, out value);

并忽略返回值。然而,实际上只返回default(TValue),而不是一些自定义默认值(更有用的是,也不是执行委托的结果)。该框架中没有任何内置的功能更强大。我建议两种扩展方法:(

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

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

当然,您可能想要进行参数检查:)


As per comments, in .Net Core 2+ / NetStandard 2.1+ / Net 5, MS added the extension method GetValueOrDefault()


TryGetValue will already assign the default value for the type to the dictionary, so you can just use:

dictionary.TryGetValue(key, out value);

and just ignore the return value. However, that really will just return default(TValue), not some custom default value (nor, more usefully, the result of executing a delegate). There's nothing more powerful built into the framework. I would suggest two extension methods:

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

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

(You may want to put argument checking in, of course :)

少女净妖师 2024-09-04 12:15:47

我确实喜欢扩展方法,但这里有一个简单的类,当我需要默认值时,我会不时使用它来处理字典。

我希望这只是 Dictionary 基类的一部分。

public class DictionaryWithDefault<TKey, TValue> : Dictionary<TKey, TValue>
{
  TValue _default;
  public TValue DefaultValue {
    get { return _default; }
    set { _default = value; }
  }
  public DictionaryWithDefault() : base() { }
  public DictionaryWithDefault(TValue defaultValue) : base() {
    _default = defaultValue;
  }
  public new TValue this[TKey key]
  {
    get { 
      TValue t;
      return base.TryGetValue(key, out t) ? t : _default;
    }
    set { base[key] = value; }
  }
}

不过要小心。通过子类化并使用 new(因为 override 在本机 Dictionary 类型上不可用),如果是 DictionaryWithDefault 对象向上转换为普通的 Dictionary,调用索引器将使用基本的 Dictionary 实现(如果缺少,则抛出异常)而不是子类的实现。

I do favor extension methods, but here's a simple class I use from time to time to handle dictionaries when I need default values.

I wish this were just part of the base Dictionary class.

public class DictionaryWithDefault<TKey, TValue> : Dictionary<TKey, TValue>
{
  TValue _default;
  public TValue DefaultValue {
    get { return _default; }
    set { _default = value; }
  }
  public DictionaryWithDefault() : base() { }
  public DictionaryWithDefault(TValue defaultValue) : base() {
    _default = defaultValue;
  }
  public new TValue this[TKey key]
  {
    get { 
      TValue t;
      return base.TryGetValue(key, out t) ? t : _default;
    }
    set { base[key] = value; }
  }
}

Beware, however. By subclassing and using new (since override is not available on the native Dictionary type), if a DictionaryWithDefault object is upcast to a plain Dictionary, calling the indexer will use the base Dictionary implementation (throwing an exception if missing) rather than the subclass's implementation.

凉城 2024-09-04 12:15:47

我创建了一个 DefaultableDictionary 来完全满足您的要求!

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace DefaultableDictionary {
    public class DefaultableDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
        private readonly IDictionary<TKey, TValue> dictionary;
        private readonly TValue defaultValue;

        public DefaultableDictionary(IDictionary<TKey, TValue> dictionary, TValue defaultValue) {
            this.dictionary = dictionary;
            this.defaultValue = defaultValue;
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
            return dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        public void Add(KeyValuePair<TKey, TValue> item) {
            dictionary.Add(item);
        }

        public void Clear() {
            dictionary.Clear();
        }

        public bool Contains(KeyValuePair<TKey, TValue> item) {
            return dictionary.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
            dictionary.CopyTo(array, arrayIndex);
        }

        public bool Remove(KeyValuePair<TKey, TValue> item) {
            return dictionary.Remove(item);
        }

        public int Count {
            get { return dictionary.Count; }
        }

        public bool IsReadOnly {
            get { return dictionary.IsReadOnly; }
        }

        public bool ContainsKey(TKey key) {
            return dictionary.ContainsKey(key);
        }

        public void Add(TKey key, TValue value) {
            dictionary.Add(key, value);
        }

        public bool Remove(TKey key) {
            return dictionary.Remove(key);
        }

        public bool TryGetValue(TKey key, out TValue value) {
            if (!dictionary.TryGetValue(key, out value)) {
                value = defaultValue;
            }

            return true;
        }

        public TValue this[TKey key] {
            get
            {
                try
                {
                    return dictionary[key];
                } catch (KeyNotFoundException) {
                    return defaultValue;
                }
            }

            set { dictionary[key] = value; }
        }

        public ICollection<TKey> Keys {
            get { return dictionary.Keys; }
        }

        public ICollection<TValue> Values {
            get
            {
                var values = new List<TValue>(dictionary.Values) {
                    defaultValue
                };
                return values;
            }
        }
    }

    public static class DefaultableDictionaryExtensions {
        public static IDictionary<TKey, TValue> WithDefaultValue<TValue, TKey>(this IDictionary<TKey, TValue> dictionary, TValue defaultValue ) {
            return new DefaultableDictionary<TKey, TValue>(dictionary, defaultValue);
        }
    }
}

该项目是 IDictionary 对象的简单装饰器和扩展方法,以使其易于使用。

DefaultableDictionary 将允许在字典周围创建一个包装器,该包装器在尝试访问不存在的键或枚举 IDictionary 中的所有值时提供默认值。

示例: vardictionary = new Dictionary().WithDefaultValue(5);

关于用法的博客文章

I created a DefaultableDictionary to do exactly what you are asking for!

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace DefaultableDictionary {
    public class DefaultableDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
        private readonly IDictionary<TKey, TValue> dictionary;
        private readonly TValue defaultValue;

        public DefaultableDictionary(IDictionary<TKey, TValue> dictionary, TValue defaultValue) {
            this.dictionary = dictionary;
            this.defaultValue = defaultValue;
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
            return dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        public void Add(KeyValuePair<TKey, TValue> item) {
            dictionary.Add(item);
        }

        public void Clear() {
            dictionary.Clear();
        }

        public bool Contains(KeyValuePair<TKey, TValue> item) {
            return dictionary.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
            dictionary.CopyTo(array, arrayIndex);
        }

        public bool Remove(KeyValuePair<TKey, TValue> item) {
            return dictionary.Remove(item);
        }

        public int Count {
            get { return dictionary.Count; }
        }

        public bool IsReadOnly {
            get { return dictionary.IsReadOnly; }
        }

        public bool ContainsKey(TKey key) {
            return dictionary.ContainsKey(key);
        }

        public void Add(TKey key, TValue value) {
            dictionary.Add(key, value);
        }

        public bool Remove(TKey key) {
            return dictionary.Remove(key);
        }

        public bool TryGetValue(TKey key, out TValue value) {
            if (!dictionary.TryGetValue(key, out value)) {
                value = defaultValue;
            }

            return true;
        }

        public TValue this[TKey key] {
            get
            {
                try
                {
                    return dictionary[key];
                } catch (KeyNotFoundException) {
                    return defaultValue;
                }
            }

            set { dictionary[key] = value; }
        }

        public ICollection<TKey> Keys {
            get { return dictionary.Keys; }
        }

        public ICollection<TValue> Values {
            get
            {
                var values = new List<TValue>(dictionary.Values) {
                    defaultValue
                };
                return values;
            }
        }
    }

    public static class DefaultableDictionaryExtensions {
        public static IDictionary<TKey, TValue> WithDefaultValue<TValue, TKey>(this IDictionary<TKey, TValue> dictionary, TValue defaultValue ) {
            return new DefaultableDictionary<TKey, TValue>(dictionary, defaultValue);
        }
    }
}

This project is a simple decorator for an IDictionary object and an extension method to make it easy to use.

The DefaultableDictionary will allow for creating a wrapper around a dictionary that provides a default value when trying to access a key that does not exist or enumerating through all the values in an IDictionary.

Example: var dictionary = new Dictionary<string, int>().WithDefaultValue(5);

Blog post on the usage as well.

凉薄对峙 2024-09-04 12:15:47

不,不存在这样的东西。扩展方法是一种可行的方法,并且您为其命名 (GetValueOrDefault) 是一个不错的选择。

No, nothing like that exists. The extension method is the way to go, and your name for it (GetValueOrDefault) is a pretty good choice.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文