API review decided to include additional overloads to enable only specifying the bool.
{
public static System.Collections.Frozen.FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue>(this System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>> source, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) where TKey : notnull { throw null; }
public static System.Collections.Frozen.FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue>(this System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>> source, System.Collections.Generic.IEqualityComparer<TKey>? comparer, bool optimizeForReading) where TKey : notnull { throw null; }
+ public static System.Collections.Frozen.FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue>(this System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>> source, bool optimizeForReading) where TKey : notnull { throw null; }
public static System.Collections.Frozen.FrozenDictionary<TKey, TSource> ToFrozenDictionary<TSource, TKey>(this System.Collections.Generic.IEnumerable<TSource> source, System.Func<TSource, TKey> keySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) where TKey : notnull { throw null; }
public static System.Collections.Frozen.FrozenDictionary<TKey, TElement> ToFrozenDictionary<TSource, TKey, TElement>(this System.Collections.Generic.IEnumerable<TSource> source, System.Func<TSource, TKey> keySelector, System.Func<TSource, TElement> elementSelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) where TKey : notnull { throw null; }
}
{
public static System.Collections.Frozen.FrozenSet<T> ToFrozenSet<T>(this System.Collections.Generic.IEnumerable<T> source, System.Collections.Generic.IEqualityComparer<T>? comparer = null) { throw null; }
public static System.Collections.Frozen.FrozenSet<T> ToFrozenSet<T>(this System.Collections.Generic.IEnumerable<T> source, System.Collections.Generic.IEqualityComparer<T>? comparer, bool optimizeForReading) { throw null; }
+ public static System.Collections.Frozen.FrozenSet<T> ToFrozenSet<T>(this System.Collections.Generic.IEnumerable<T> source, bool optimizeForReading) { throw null; }
}
public abstract partial class FrozenSet<T> : System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.ISet<T>, System.Collections.ICollection, System.Collections.IEnumerable
{
/// <summary>Creates a <see cref="FrozenDictionary{TKey, TValue}"/> with the specified key/value pairs.</summary>
/// <param name="source">The key/value pairs to use to populate the dictionary.</param>
+ /// <param name="optimizeForReading">
+ /// <see langword="true"/> to do more work as part of dictionary construction to optimize for subsequent reading of the data;
+ /// <see langword="false"/> to prefer making construction more efficient. The default is <see langword="false"/>.
+ /// </param>
+ /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
+ /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
+ /// <remarks>
+ /// <para>
+ /// Frozen collections are immutable and may be optimized for situations where a collection is created very infrequently but
+ /// is used very frequently at runtime. Setting <paramref name="optimizeForReading"/> to <see langword="true"/> will result in a
+ /// relatively high cost to create the collection in exchange for improved performance when subsequently using the collection.
+ /// Using <see langword="true"/> is ideal for collections that are created once, potentially at the startup of a service, and then
+ /// used throughout the remainder of the lifetime of the service. Because of the high cost of creation, frozen collections should
+ /// only be initialized with trusted input.
+ /// </para>
+ /// <para>
+ /// If the same key appears multiple times in the input, the latter one in the sequence takes precedence. This differs from
+ /// <see cref="M:System.Linq.Enumerable.ToDictionary"/>, with which multiple duplicate keys will result in an exception.
+ /// </para>
+ /// </remarks>
+ /// <returns>A <see cref="FrozenDictionary{TKey, TValue}"/> that contains the specified keys and values.</returns>
+ public static FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source, bool optimizeForReading)
+ where TKey : notnull =>
+ ToFrozenDictionary(source, null, optimizeForReading);
+
+ /// <summary>Creates a <see cref="FrozenDictionary{TKey, TValue}"/> with the specified key/value pairs.</summary>
+ /// <param name="source">The key/value pairs to use to populate the dictionary.</param>
/// <param name="comparer">The comparer implementation to use to compare keys for equality. If null, <see cref="EqualityComparer{TKey}.Default"/> is used.</param>
/// <param name="optimizeForReading">
/// <see langword="true"/> to do more work as part of dictionary construction to optimize for subsequent reading of the data;
/// <summary>Creates a <see cref="FrozenSet{T}"/> with the specified values.</summary>
/// <param name="source">The values to use to populate the set.</param>
+ /// <param name="optimizeForReading">
+ /// <see langword="true"/> to do more work as part of set construction to optimize for subsequent reading of the data;
+ /// <see langword="false"/> to prefer making construction more efficient. The default is <see langword="false"/>.
+ /// </param>
+ /// <typeparam name="T">The type of the values in the set.</typeparam>
+ /// <returns>A frozen set.</returns>
+ /// <remarks>
+ /// Frozen collections are immutable and may be optimized for situations where a collection is created very infrequently but
+ /// is used very frequently at runtime. Setting <paramref name="optimizeForReading"/> to <see langword="true"/> will result in a
+ /// relatively high cost to create the collection in exchange for improved performance when subsequently using the collection.
+ /// Using <see langword="true"/> is ideal for collections that are created once, potentially at the startup of a service, and then
+ /// used throughout the remainder of the lifetime of the service. Because of the high cost of creation, frozen collections should
+ /// only be initialized with trusted input.
+ /// </remarks>
+ public static FrozenSet<T> ToFrozenSet<T>(this IEnumerable<T> source, bool optimizeForReading) =>
+ ToFrozenSet(source, null, optimizeForReading);
+
+ /// <summary>Creates a <see cref="FrozenSet{T}"/> with the specified values.</summary>
+ /// <param name="source">The values to use to populate the set.</param>
/// <param name="comparer">The comparer implementation to use to compare values for equality. If null, <see cref="EqualityComparer{T}.Default"/> is used.</param>
/// <param name="optimizeForReading">
/// <see langword="true"/> to do more work as part of set construction to optimize for subsequent reading of the data;
AssertExtensions.Throws<ArgumentNullException>("source", () => ((Dictionary<TKey, TValue>)null).ToFrozenDictionary());
AssertExtensions.Throws<ArgumentNullException>("source", () => ((Dictionary<TKey, TValue>)null).ToFrozenDictionary(null));
AssertExtensions.Throws<ArgumentNullException>("source", () => ((Dictionary<TKey, TValue>)null).ToFrozenDictionary(EqualityComparer<TKey>.Default));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((Dictionary<TKey, TValue>)null).ToFrozenDictionary(null, false));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((Dictionary<TKey, TValue>)null).ToFrozenDictionary(null, true));
AssertExtensions.Throws<ArgumentNullException>("keySelector", () => Enumerable.Empty<int>().ToFrozenDictionary((Func<int, int>)null));
AssertExtensions.Throws<ArgumentNullException>("keySelector", () => Enumerable.Empty<int>().ToFrozenDictionary((Func<int, int>)null, EqualityComparer<int>.Default));
Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(null));
Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(null, false));
Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(null, true));
+ Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(false));
+ Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(true));
Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(EqualityComparer<TKey>.Default));
Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(EqualityComparer<TKey>.Default, false));
Assert.Same(FrozenDictionary<TKey, TValue>.Empty, FrozenDictionary<TKey, TValue>.Empty.ToFrozenDictionary(EqualityComparer<TKey>.Default, true));
Assert.NotSame(frozen, frozen.ToFrozenDictionary(NonDefaultEqualityComparer<TKey>.Instance));
}
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void ToFrozenDictionary_BoolArg_UsesDefaultComparer(bool optimizeForReading)
+ {
+ Dictionary<TKey, TValue> source = Enumerable.Range(0, 4).ToDictionary(CreateTKey, CreateTValue);
+
+ FrozenDictionary<TKey, TValue> frozen1 = source.ToFrozenDictionary(optimizeForReading);
+
+ Assert.Same(EqualityComparer<TKey>.Default, frozen1.Comparer);
+ }
+
[Fact]
public void ToFrozenDictionary_KeySelector_ResultsAreUsed()
{
public void NullSource_ThrowsException()
{
AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet());
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(false));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(true));
AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(null));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(null, false));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(null, true));
AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(EqualityComparer<T>.Default));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(EqualityComparer<T>.Default, false));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => ((HashSet<T>)null).ToFrozenSet(EqualityComparer<T>.Default, true));
}
[Fact]
Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(null));
Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(null, false));
Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(null, true));
+ Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(false));
+ Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(true));
Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(EqualityComparer<T>.Default));
Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(EqualityComparer<T>.Default, false));
Assert.Same(FrozenSet<T>.Empty, FrozenSet<T>.Empty.ToFrozenSet(EqualityComparer<T>.Default, true));
Assert.NotSame(frozen, frozen.ToFrozenSet(NonDefaultEqualityComparer<T>.Instance));
}
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void ToFrozenSet_BoolArg_UsesDefaultComparer(bool optimizeForReading)
+ {
+ HashSet<T> source = new HashSet<T>(Enumerable.Range(0, 4).Select(CreateT));
+
+ FrozenSet<T> frozen = source.ToFrozenSet(optimizeForReading);
+
+ Assert.Same(EqualityComparer<T>.Default, frozen.Comparer);
+ }
+
public static IEnumerable<object[]> LookupItems_AllItemsFoundAsExpected_MemberData() =>
from size in new[] { 0, 1, 2, 10, 999, 1024 }
from comparer in new IEqualityComparer<T>[] { null, EqualityComparer<T>.Default, NonDefaultEqualityComparer<T>.Instance }