【问题标题】:How to create an empty IReadOnlyCollection如何创建一个空的 IReadOnlyCollection
【发布时间】:2014-08-10 09:46:59
【问题描述】:

我正在为MultiValueDictionary 创建一个扩展方法来封装频繁的ContainsKey 检查,我想知道创建空IReadOnlyCollection 的最佳方法是什么?

到目前为止我使用的是new List<TValue>(0).AsReadOnly(),但必须有更好的方法,相当于IEnumerableEnumerable.Empty

public static IReadOnlyCollection<TValue> GetValuesOrEmpty<TKey, TValue>(this MultiValueDictionary<TKey, TValue> multiValueDictionary, TKey key)
{            
    IReadOnlyCollection<TValue> values;
    return !multiValueDictionary.TryGetValue(key, out values) ? new List<TValue>(0).AsReadOnly() : values;
}

【问题讨论】:

  • 并非如此,因为IReadOnlyCollection 只是一个包装器。您可以考虑返回一个IEnumerable&lt;Value&gt;,或者通常没有AddRemove 方法。

标签: c# .net readonly-collection multi-value-dictionary


【解决方案1】:

编辑:新的 .Net 4.6 添加了一个 API 来获取一个空数组:Array.Empty&lt;T&gt; 和数组实现 IReadOnlyCollection&lt;T&gt;。这也减少了分配,因为它只创建一次实例:

IReadOnlyCollection<int> emptyReadOnlyCollection = Array.Empty<int>();

我最终做的是使用new TElement[0] 模仿Enumerable.Empty 的实现:

public static class ReadOnlyCollection
{
    public static IReadOnlyCollection<TResult> Empty<TResult>()
    {
        return EmptyReadOnlyCollection<TResult>.Instance;
    }

    private static class EmptyReadOnlyCollection<TElement>
    {
        static volatile TElement[] _instance;

        public static IReadOnlyCollection<TElement> Instance
        {
            get { return _instance ?? (_instance = new TElement[0]); }
        }
    }
}

用法:

IReadOnlyCollection<int> emptyReadOnlyCollection = ReadOnlyCollection.Empty<int>();

【讨论】:

  • 看起来不错。但是正确使用volatile 很难(这里没问题),但我想坚持使用更高级别的api,并选择private static Lazy&lt;IReadOnlyCollection&lt;TElement&gt;&gt; _EmptyCollection = new Lazy&lt;IReadOnlyCollection&lt;TElement&gt;&gt;(()=&gt; new TElement[0]); 并在你的 Empty() 方法中然后使用return _EmptyCollection.Value;
【解决方案2】:

据我所知,没有内置方法(有兴趣知道是否有)。也就是说,您可以使用以下内容:

IReadOnlyCollection<TValue> readonlyCollection = new ReadOnlyCollection<TValue>(new TValue[] { });

您可以选择缓存结果,因为它是一个空数组上的ReadOnlyCollection,无论您有多少实例,它都将始终相同。

【讨论】:

    【解决方案3】:

    我认为对于只读集合没有像 Enumerable.Empty 这样的东西,但是:

    • List&lt;T&gt; 已经实现了IReadOnlyCollection&lt;T&gt;,因此您可以通过不调用AsReadOnly() 并简单地转换列表来避免一个对象分配。这在理论上不太“安全”,但在实践中几乎不重要。

    • 或者,您可以缓存返回的 ReadOnlyCollection 以避免任何对象分配(缓存对象除外)。

    【讨论】:

    • 结合了两个答案并使用了return new TValue[0]
    • @I3arnon:如果你给你的类一个private static IReadOnlyCollection&lt;TValue&gt; _EmptyCollection = new TValue[0],你只需要在没有可用值时实例化这个空数组一次。更进一步,您甚至可以将其打包到 Lazy&lt;T&gt; 中,这样只会在第一次需要时创建这个空数组。
    • Nit:甚至不需要将List&lt;T&gt; 的表达式“转换”为List&lt;T&gt;(但不是IList&lt;T&gt;)实现IReadOnlyCollection&lt;T&gt;
    【解决方案4】:

    return new List&lt;XElement&gt;().AsReadOnly();

    【讨论】:

      【解决方案5】:

      这个和 Enumerable.Empty 语法相似的东西怎么样:

      /// <summary>
      /// Contains a method used to provide an empty, read-only collection.
      /// </summary>
      public static class ReadOnlyCollection
      {
          /// <summary>
          /// Returns an empty, read-only collection that has the specified type argument.
          /// </summary>
          /// <typeparam name="T">
          /// The type to assign to the type parameter of the returned generic read-only collection.
          /// </typeparam>
          /// <returns>
          /// An empty, read-only collection whose type argument is T.
          /// </returns>
          public static IReadOnlyCollection<T> Empty<T>()
          {
              return CachedValueProvider<T>.Value;
          }
      
          /// <summary/>
          static class CachedValueProvider<T>
          {
              /// <summary/>
              public static readonly IReadOnlyCollection<T> Value = new T[0];
          }
      }
      

      这样使用:

      IReadOnlyCollection<int> empty = ReadOnlyCollection.Empty<int>();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-23
        • 1970-01-01
        • 2022-11-11
        • 1970-01-01
        • 2020-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多