Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public static RuntimeTypeInfo CastToRuntimeTypeInfo(this Type type)

public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(this IEnumerable<T> enumeration)
{
return new ReadOnlyCollection<T>(enumeration.ToArray());
return Array.AsReadOnly(enumeration.ToArray());
}

public static MethodInfo FilterAccessor(this MethodInfo accessor, bool nonPublic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2099,8 +2099,7 @@ private ReadOnlyCollection<TKey> GetKeys()

if (count == 0)
{
// TODO https://github.com/dotnet/runtime/issues/76028: Replace with ReadOnlyCollection<TKey>.Empty.
return Array.Empty<TKey>().AsReadOnly();
return ReadOnlyCollection<TKey>.Empty;
}

var keys = new TKey[count];
Expand Down Expand Up @@ -2141,8 +2140,7 @@ private ReadOnlyCollection<TValue> GetValues()

if (count == 0)
{
// TODO https://github.com/dotnet/runtime/pull/76097: Replace with ReadOnlyCollection<TValue>.Empty.
return Array.Empty<TValue>().AsReadOnly();
return ReadOnlyCollection<TValue>.Empty;
}

var values = new TValue[count];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(this IEnumerable<T>
{
ArgumentNullException.ThrowIfNull(source);

return new ReadOnlyCollection<T>(source.AsArray());
return Array.AsReadOnly(source.AsArray());
}

public static IEnumerable<T>? ConcatAllowingNull<T>(this IEnumerable<T>? source, IEnumerable<T>? second)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ internal CompositionException(string? message, Exception? innerException, IEnume
: base(message, innerException)
{
Requires.NullOrNotNullElements(errors, nameof(errors));
_errors = new ReadOnlyCollection<CompositionError>(errors == null ? Array.Empty<CompositionError>() : errors.ToArray<CompositionError>());
_errors = Array.AsReadOnly(errors == null ? Array.Empty<CompositionError>() : errors.ToArray<CompositionError>());
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public AggregateExportProvider(params ExportProvider[]? providers)
}

_providers = copiedProviders;
_readOnlyProviders = new ReadOnlyCollection<ExportProvider>(_providers);
_readOnlyProviders = Array.AsReadOnly(_providers);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public CompositionContainer(ComposablePartCatalog? catalog, CompositionOptions c
_rootProvider.ExportsChanged += OnExportsChangedInternal;
_rootProvider.ExportsChanging += OnExportsChangingInternal;

_providers = (providers != null) ? new ReadOnlyCollection<ExportProvider>((ExportProvider[])providers.Clone()) : EmptyProviders;
_providers = (providers != null) ? Array.AsReadOnly((ExportProvider[])providers.Clone()) : EmptyProviders;
}

internal CompositionOptions CompositionOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ public void Refresh()
_catalogCollection.Remove(catalogToRemove.Item2);
}

_loadedFiles = afterFiles.ToReadOnlyCollection();
_loadedFiles = Array.AsReadOnly(afterFiles);

// Lastly complete any changes added to the atomicComposition during the change event
atomicComposition.Complete();
Expand Down Expand Up @@ -756,7 +756,7 @@ private void Initialize(string path, string searchPattern)
_assemblyCatalogs = new Dictionary<string, AssemblyCatalog>();
_catalogCollection = new ComposablePartCatalogCollection(null, null, null);

_loadedFiles = GetFiles().ToReadOnlyCollection();
_loadedFiles = Array.AsReadOnly(GetFiles());

foreach (string file in _loadedFiles)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ public SharingBoundaryAttribute(params string[] sharingBoundaryNames)
/// <summary>
/// Boundaries implemented by the created ExportLifetimeContext{T}s.
/// </summary>
public ReadOnlyCollection<string> SharingBoundaryNames => new ReadOnlyCollection<string>(_sharingBoundaryNames);
public ReadOnlyCollection<string> SharingBoundaryNames => Array.AsReadOnly(_sharingBoundaryNames);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@
<Compile Include="System\Runtime\CompilerServices\TrueReadOnlyCollection.cs" />
<Compile Include="System\Dynamic\Utils\CachedReflectionInfo.cs" />
<Compile Include="System\Dynamic\Utils\CollectionExtensions.cs" />
<Compile Include="System\Dynamic\Utils\EmptyReadOnlyCollection.cs" />
<Compile Include="System\Dynamic\UpdateDelegates.Generated.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,26 @@ public static T[] RemoveLast<T>(this T[] array)
/// </summary>
public static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T>? enumerable)
{
if (enumerable == null)
if (enumerable != null && enumerable != ReadOnlyCollection<T>.Empty)
{
return EmptyReadOnlyCollection<T>.Instance;
}
if (enumerable is TrueReadOnlyCollection<T> troc)
{
return troc;
}

if (enumerable is TrueReadOnlyCollection<T> troc)
{
return troc;
}
if (enumerable is ReadOnlyCollectionBuilder<T> builder)
{
return builder.ToReadOnlyCollection();
}

if (enumerable is ReadOnlyCollectionBuilder<T> builder)
{
return builder.ToReadOnlyCollection();
T[] array = enumerable.ToArray();
if (array.Length != 0)
{
return new TrueReadOnlyCollection<T>(array);
}
}

T[] array = enumerable.ToArray();
return array.Length == 0 ?
EmptyReadOnlyCollection<T>.Instance :
new TrueReadOnlyCollection<T>(array);
return ReadOnlyCollection<T>.Empty;
}

// We could probably improve the hashing here
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ internal virtual ReadOnlyCollection<Expression> GetOrMakeExpressions()

internal virtual ReadOnlyCollection<ParameterExpression> GetOrMakeVariables()
{
return EmptyReadOnlyCollection<ParameterExpression>.Instance;
return ReadOnlyCollection<ParameterExpression>.Empty;
}

/// <summary>
Expand Down Expand Up @@ -913,7 +913,7 @@ public static BlockExpression Block(params Expression[] expressions)
/// <returns>The created <see cref="BlockExpression"/>.</returns>
public static BlockExpression Block(IEnumerable<Expression> expressions)
{
return Block(EmptyReadOnlyCollection<ParameterExpression>.Instance, expressions);
return Block(ReadOnlyCollection<ParameterExpression>.Empty, expressions);
}

/// <summary>
Expand All @@ -936,7 +936,7 @@ public static BlockExpression Block(Type type, params Expression[] expressions)
/// <returns>The created <see cref="BlockExpression"/>.</returns>
public static BlockExpression Block(Type type, IEnumerable<Expression> expressions)
{
return Block(type, EmptyReadOnlyCollection<ParameterExpression>.Instance, expressions);
return Block(type, ReadOnlyCollection<ParameterExpression>.Empty, expressions);
}

/// <summary>
Expand Down Expand Up @@ -1089,7 +1089,7 @@ private static BlockExpression GetOptimizedBlockExpression(IReadOnlyList<Express
{
return expressions.Count switch
{
0 => BlockCore(typeof(void), EmptyReadOnlyCollection<ParameterExpression>.Instance, EmptyReadOnlyCollection<Expression>.Instance),
0 => BlockCore(typeof(void), ReadOnlyCollection<ParameterExpression>.Empty, ReadOnlyCollection<Expression>.Empty),
2 => new Block2(expressions[0], expressions[1]),
3 => new Block3(expressions[0], expressions[1], expressions[2]),
4 => new Block4(expressions[0], expressions[1], expressions[2], expressions[3]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,24 @@ internal HoistedLocals(HoistedLocals? parent, ReadOnlyCollection<ParameterExpres
vars = vars.AddFirst(parent.SelfVariable);
}

Dictionary<Expression, int> indexes = new Dictionary<Expression, int>(vars.Count);
for (int i = 0; i < vars.Count; i++)
if (vars.Count != 0)
{
indexes.Add(vars[i], i);
Dictionary<Expression, int> indexes = new Dictionary<Expression, int>(vars.Count);
for (int i = 0; i < vars.Count; i++)
{
indexes.Add(vars[i], i);
}

Indexes = new ReadOnlyDictionary<Expression, int>(indexes);
}
else
{
Indexes = ReadOnlyDictionary<Expression, int>.Empty;
}

SelfVariable = Expression.Variable(typeof(object[]), name: null);
Parent = parent;
Variables = vars;
Indexes = new ReadOnlyDictionary<Expression, int>(indexes);
SelfVariable = Expression.Variable(typeof(object[]), name: null);
}

internal ParameterExpression? ParentVariable => Parent?.SelfVariable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public InvocationExpression0(Expression lambda, Type returnType)

internal override ReadOnlyCollection<Expression> GetOrMakeArguments()
{
return EmptyReadOnlyCollection<Expression>.Instance;
return ReadOnlyCollection<Expression>.Empty;
}

public override Expression GetArgument(int index)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ internal override ParameterExpression GetParameter(int index)
throw Error.ArgumentOutOfRange(nameof(index));
}

internal override ReadOnlyCollection<ParameterExpression> GetOrMakeParameters() => EmptyReadOnlyCollection<ParameterExpression>.Instance;
internal override ReadOnlyCollection<ParameterExpression> GetOrMakeParameters() => ReadOnlyCollection<ParameterExpression>.Empty;

internal override Expression<TDelegate> Rewrite(Expression body, ParameterExpression[]? parameters)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static ListInitExpression ListInit(NewExpression newExpression, IEnumerab
ReadOnlyCollection<Expression> initializerlist = initializers.ToReadOnly();
if (initializerlist.Count == 0)
{
return new ListInitExpression(newExpression, EmptyReadOnlyCollection<ElementInit>.Instance);
return new ListInitExpression(newExpression, ReadOnlyCollection<ElementInit>.Empty);
}

MethodInfo? addMethod = FindMethod(newExpression.Type, "Add", null, new Expression[] { initializerlist[0] }, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ public override Expression GetArgument(int index)

internal override ReadOnlyCollection<Expression> GetOrMakeArguments()
{
return EmptyReadOnlyCollection<Expression>.Instance;
return ReadOnlyCollection<Expression>.Empty;
}

internal override bool SameArguments(ICollection<Expression>? arguments) =>
Expand Down Expand Up @@ -622,7 +622,7 @@ public override Expression GetArgument(int index)

internal override ReadOnlyCollection<Expression> GetOrMakeArguments()
{
return EmptyReadOnlyCollection<Expression>.Instance;
return ReadOnlyCollection<Expression>.Empty;
}

internal override bool SameArguments(ICollection<Expression>? arguments) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public static NewExpression New(
{
throw Error.TypeMissingDefaultConstructor(type, nameof(type));
}
return new NewValueTypeExpression(type, EmptyReadOnlyCollection<Expression>.Instance, null);
return new NewValueTypeExpression(type, ReadOnlyCollection<Expression>.Empty, null);
}

[RequiresUnreferencedCode(PropertyFromAccessorRequiresUnreferencedCode)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,11 @@ public T[] ToArray()
/// <returns>A new instance of <see cref="ReadOnlyCollection{T}"/>.</returns>
public ReadOnlyCollection<T> ToReadOnlyCollection()
{
if (_size == 0)
{
return ReadOnlyCollection<T>.Empty;
}

// Can we use the stored array?
T[] items;
if (_size == _items.Length)
Expand Down
9 changes: 3 additions & 6 deletions src/libraries/System.Linq/tests/ToListTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,16 @@ public void ToList_IListWhereSelect(int[] sourceIntegers, string[] convertedStri
var sourceList = new ReadOnlyCollection<int>(sourceIntegers);
var convertedList = new ReadOnlyCollection<string>(convertedStrings);

var emptyIntegersList = new ReadOnlyCollection<int>(Array.Empty<int>());
var emptyStringsList = new ReadOnlyCollection<string>(Array.Empty<string>());

Assert.Equal(convertedList, sourceList.Select(i => i.ToString()).ToList());

Assert.Equal(sourceList, sourceList.Where(i => true).ToList());
Assert.Equal(emptyIntegersList, sourceList.Where(i => false).ToList());
Assert.Equal(ReadOnlyCollection<int>.Empty, sourceList.Where(i => false).ToList());

Assert.Equal(convertedList, sourceList.Where(i => true).Select(i => i.ToString()).ToList());
Assert.Equal(emptyStringsList, sourceList.Where(i => false).Select(i => i.ToString()).ToList());
Assert.Equal(ReadOnlyCollection<string>.Empty, sourceList.Where(i => false).Select(i => i.ToString()).ToList());

Assert.Equal(convertedList, sourceList.Select(i => i.ToString()).Where(s => s != null).ToList());
Assert.Equal(emptyStringsList, sourceList.Select(i => i.ToString()).Where(s => s == null).ToList());
Assert.Equal(ReadOnlyCollection<string>.Empty, sourceList.Select(i => i.ToString()).Where(s => s == null).ToList());
}

[Fact]
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.ObjectModel/ref/System.ObjectModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ protected override void SetItem(int index, T item) { }
public partial class ReadOnlyObservableCollection<T> : System.Collections.ObjectModel.ReadOnlyCollection<T>, System.Collections.Specialized.INotifyCollectionChanged, System.ComponentModel.INotifyPropertyChanged
{
public ReadOnlyObservableCollection(System.Collections.ObjectModel.ObservableCollection<T> list) : base (default(System.Collections.Generic.IList<T>)) { }
public static new System.Collections.ObjectModel.ReadOnlyObservableCollection<T> Empty { get { throw null; } }
protected virtual event System.Collections.Specialized.NotifyCollectionChangedEventHandler? CollectionChanged { add { } remove { } }
protected virtual event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged { add { } remove { } }
event System.Collections.Specialized.NotifyCollectionChangedEventHandler? System.Collections.Specialized.INotifyCollectionChanged.CollectionChanged { add { } remove { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public ReadOnlyObservableCollection(ObservableCollection<T> list) : base(list)
((INotifyPropertyChanged)Items).PropertyChanged += new PropertyChangedEventHandler(HandlePropertyChanged);
}

/// <summary>Gets an empty <see cref="ReadOnlyObservableCollection{T}"/>.</summary>
/// <value>An empty <see cref="ReadOnlyObservableCollection{T}"/>.</value>
/// <remarks>The returned instance is immutable and will always be empty.</remarks>
public static new ReadOnlyObservableCollection<T> Empty { get; } = new ReadOnlyObservableCollection<T>(new ObservableCollection<T>());

/// <summary>
/// CollectionChanged event (per <see cref="INotifyCollectionChanged" />).
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ public static void CtorTests_Negative()
AssertExtensions.Throws<ArgumentNullException>("dictionary", () => new ReadOnlyDictionary<int, string>(null));
}

[Fact]
public static void Empty_Idempotent()
{
Assert.NotNull(ReadOnlyDictionary<string, int>.Empty);
Assert.Equal(0, ReadOnlyDictionary<string, int>.Empty.Count);
Assert.Same(ReadOnlyDictionary<string, int>.Empty, ReadOnlyDictionary<string, int>.Empty);
}

/// <summary>
/// Tests that true is returned when the key exists in the dictionary
/// and false otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ public static void Ctor_Tests_Negative()
AssertExtensions.Throws<ArgumentNullException>("list", () => new ReadOnlyObservableCollection<string>(null));
}

[Fact]
public static void Empty_Idempotent()
{
Assert.NotNull(ReadOnlyObservableCollection<int>.Empty);
Assert.Equal(0, ReadOnlyObservableCollection<int>.Empty.Count);
Assert.Same(ReadOnlyObservableCollection<int>.Empty, ReadOnlyObservableCollection<int>.Empty);
}

[Fact]
public static void GetItemTests()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public ReadOnlyCollection(IList<T> list)
this.list = list;
}

// TODO https://github.com/dotnet/runtime/issues/76028: Make this public.
/// <summary>Gets an empty <see cref="ReadOnlyCollection{T}"/>.</summary>
/// <value>An empty <see cref="ReadOnlyCollection{T}"/>.</value>
/// <remarks>The returned instance is immutable and will always be empty.</remarks>
internal static ReadOnlyCollection<T> Empty { get; } = new ReadOnlyCollection<T>(Array.Empty<T>());
public static ReadOnlyCollection<T> Empty { get; } = new ReadOnlyCollection<T>(Array.Empty<T>());

public int Count => list.Count;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
m_dictionary = dictionary;
}

/// <summary>Gets an empty <see cref="ReadOnlyDictionary{TKey, TValue}"/>.</summary>
/// <value>An empty <see cref="ReadOnlyDictionary{TKey, TValue}"/>.</value>
/// <remarks>The returned instance is immutable and will always be empty.</remarks>
public static ReadOnlyDictionary<TKey, TValue> Empty { get; } = new ReadOnlyDictionary<TKey, TValue>(new Dictionary<TKey, TValue>());

protected IDictionary<TKey, TValue> Dictionary => m_dictionary;

public KeyCollection Keys => _keys ??= new KeyCollection(m_dictionary.Keys);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ internal List<DataMember>? Members
set => _helper.Members = value;
}

public override ReadOnlyCollection<DataMember> DataMembers => (Members == null) ? DataContract.s_emptyDataMemberList : Members.AsReadOnly();
public override ReadOnlyCollection<DataMember> DataMembers => (Members == null) ? ReadOnlyCollection<DataMember>.Empty : Members.AsReadOnly();

internal XmlDictionaryString?[]? ChildElementNamespaces
{
Expand Down
Loading