Runtime: Suggestion: Enumerable.ToReadOnly

Created on 9 Aug 2017  路  12Comments  路  Source: dotnet/runtime

Please include a LINQ extension ToReadOnly (and ToReadOnlyAsync (for IQueryable<T>, in System.Data.Entity.QueryableExtensions), which should return a readonly list of the enumerated result.

api-needs-work area-System.Linq

Most helpful comment

Being managed/provided by IoC means nothing about thread safety, including if you instantiate one container for one contained object. Generally speaking IoC managers aren't going to know about the threading conditions of where the object is being used, and expect you to handle things accordingly.
Still, assuming your base collection is stable, effects would be minimal, mostly limited to occasionally building the collection an extra time or two.

But, and I should have restated this earlier, what you really have here is an ImmutableList<T>. Ignoring any threading side-effects, your collection is stable/unchanging once first observed, as opposed to a ReadOnly<T>, which implies that the underlying data might be modified internally. There's even a ToImmutableList<T>() extension method, which would cover your usecase nicely. ImmutableList<T> also implements IReadOnlyList<T>, so would functionally be the same thing (although your API would be clearer by returning IImutableList<T> instead).
What I'm saying is, this issue should be closed because the functionality already exists.

All 12 comments

ToReadOnlyAsync wouldn't make a lot of sense as a general linq method for the same reason ToListAsync doesn't, but only be appropriate for providers that will always or almost-always be doing some I/O-bound work, such as Entity Framework (which again, does have a ToListAsync.

Just forget the Async for now.

I have an API I provide many lazy-loaded sets of values that shouldn't be changed, It's all operated by LINQ, and my code is flooded with _myList = query.ToList().AsReadOnly() calls.
I'm merely asking for a syntactic sugar.

Surely this would be easy enough for you to implement yourself as an extension method?

.... but after query.ToList().AsReadOnly() it's no longer lazy. For that matter, if you have some sort of query it's already read-only anyways (can you just expose an IEnumerable<>?).
If you're really materializing the collection like that, I'd expect an immutable collection to be a better fit, intent wise.

@Clockwork-Muse I meant I'm using lazy properties that look like this, I wasn't talking about deferred execution of IEnumerable<T>, in my case, I'm explicitly materializing and iterating throughout the query results.

IList<ItemType> _ItemTypes;
public IList<ItemType> ItemTypes;
{
  get
  {
    if (_ItemTypes == null)
    {
       var query = .....
       _ItemTypes = query.ToList().AsReadOnly();
    }
    return _ItemTypes;    
  }
}

A static class somewhere in your project with

```C#
public static ReadOnlyCollection ToReadOnly(this IEnumerable source)
=> source.ToList().AsReadOnly();

public static async Task> ToReadOnlyAsync(this IQueryable source)
=> (await source.ToListAsync().ConfigureAwait(false)).AsReadOnly();
```

would be enough to provide this. Optimisation possibilities would include using a singleton empty collection when appropriate. The question, it seems to me, is whether the former is generally useful enough to provide in corefx, given that it's easy enough to do for oneself (and potentially the same question about the latter for the EF people).

I know I can make an ex. method, question is if anyone needs to have a belt of ex. methods anywhere or we can have it shipped out the box.

Ah, okay.

(side note: that way of writing a lazy generation isn't threadsafe, but I don't know your usecase well enough to say whether it's good enough for your purpose)

It's not supposed to be thread safe. Single threaded app, and the containing class is managed and provided via IoC, and is only accessed by a single thread one at a time.

Being managed/provided by IoC means nothing about thread safety, including if you instantiate one container for one contained object. Generally speaking IoC managers aren't going to know about the threading conditions of where the object is being used, and expect you to handle things accordingly.
Still, assuming your base collection is stable, effects would be minimal, mostly limited to occasionally building the collection an extra time or two.

But, and I should have restated this earlier, what you really have here is an ImmutableList<T>. Ignoring any threading side-effects, your collection is stable/unchanging once first observed, as opposed to a ReadOnly<T>, which implies that the underlying data might be modified internally. There's even a ToImmutableList<T>() extension method, which would cover your usecase nicely. ImmutableList<T> also implements IReadOnlyList<T>, so would functionally be the same thing (although your API would be clearer by returning IImutableList<T> instead).
What I'm saying is, this issue should be closed because the functionality already exists.

@Clockwork-Muse
+1 for ImmutableList<T>.

I'm closing this per @Clockwork-Muse's conclusion. Please feel free to reactivate if you disagree.

Was this page helpful?
0 / 5 - 0 ratings