-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an ISet<T>.AsReadOnly()
extension method
#29387
Comments
Thanks @vanillajonathan I think this makes sense. I've marked the issue as api ready for review. |
Returning What about a new type |
Feedback - what are you actually trying to do here?
If you want to create a |
I want to create a entity in Entity Framework Core. EF Core internally treats collections as hash sets but they are commonly exposed as I intend to employ domain-driven design (DDD), so I do not want to expose it as a Since |
In your scenario, accessing the Example: public class Blog
{
private List<Post> _posts = new List<Post>();
private ReadOnlyCollection<Post> _postsAsReadOnlyCollection = new ReadOnlyCollection<Post>(_posts);
public IReadOnlyCollection<Post> Posts => _postsAsReadOnlyCollection;
public void AddPost(Post post)
{
// business logic here
_posts.Add(post);
}
} Or, if you really want to use public class Blog
{
private HashSet<Post> _posts = new HashSet<Post>();
private ReadOnlyCollection<Post> _cachedROC = null;
public IReadOnlyCollection<Post> Posts => _cachedROC ?? (_cachedROC = new ReadOnlyCollection<T>(_posts.ToArray()));
public void AddPost(Post post)
{
// business logic
_posts.Add(post);
_cachedROC = null; // clear cached value if it exists
}
} |
I was under the impression that In the first of your examples I would need two private and one public instead of just one public or one private setter. Also it uses List while EF Core internally uses HashSet so the performance may differ. In the second of your examples, it introduces caching into the business entity. Both of these are undesirable. Could |
Yes, it must create a brand new collection every time. The reason for this is that |
This raises the question, should |
No. |
Good point. Could With a public class Blog
{
private List<Post> _posts;
public IReadOnlyCollection<Post> Posts => _posts?.AsReadOnly();
} Which you cannot do as cleanly when using a |
Which brings us back to the original response on the thread... given your scenario it really would just be easier to have a property that directly casts the
So don't cast it back? :) |
I wouldn't typecast it back to a |
So what is your concrete proposal then? Are you proposing a new type |
Well I don't know how feasible it is, but I expected the |
And what would be the return type of |
You're right, it cannot return a Maybe it is weird that |
Yeah, in hindsight it may have made sense to have two types |
Maybe things can be fixed for .NET 5? This would be nice for developers using Entity Framework Core and who wish to implement domain-driven design (DDD). |
That's not the type of breaking change we would take in .NET 5. |
What about ReadOnlySet which can wrap any ISet ? |
Assuming we decided to add something like this, I think it should return an |
Wouldn’t it be better for this not to be part of the class but just an extension? Especially since public static class HashSetExtensions {
public static IReadOnlySet<T> AsReadOnlySet(
this IReadOnlySet<T> readOnlySet) {
return readOnlySet;
}
} Since a direct cast exists, the rationale for including the above API would be the same as for having For wrapping public static class HashSetExtensions {
public static IReadOnlySet<T> AsReadOnlySet(
this ISet<T> set) {
return new ReadOnlySetAdapter<T>(set);
}
class ReadOnlySetAdapter<T> : IReadOnlySet<T> {
…
}
} |
Closing -- would not support exposing an extension method as proposed. It would need to return |
|
I've updated the API proposal to add an extension method in |
ISet<T>.AsReadOnly()
extension method
namespace System.Collections.Generic;
public partial class CollectionExtensions
{
// Existing:
// public ReadOnlyCollection<T> AsReadOnly(this IList<T> list);
// public ReadOnlyDictionary<T> AsReadOnly(this IDictionary<T> dictionary);
public ReadOnlySet<T> AsReadOnly(this ISet<T> set);
} |
Was there any reason this extension didn't make it into .NET 9? |
Read the discussion in the linked PR #106037 |
The
List<>
class have aAsReadOnly
method to turn the collection into aReadOnlyCollection
, butHashSet<>
does not have any such method.Rationale and usage
Allows Entity Framework Core to expose a collection navigation property as a
IReadOnlyCollection
when backing it with a private backing field declared as aHashSet
.Proposed API
namespace System.Collections.Generic; public class CollectionExtensions { public ReadOnlyCollection<T> AsReadOnly(this IList<T> list); public ReadOnlyDictionary<T> AsReadOnly(this IDictionary<T> dictionary); + public ReadOnlySet<T> AsReadOnly(this ISet<T> set); }
The text was updated successfully, but these errors were encountered: