"using" statement as a part of "foreach" #8797
Replies: 22 comments
-
foreach (var adapter in stuffAdapterSeq)
{
using (adapter)
{
// get stuff
}
} I don't see what's wrong with this? |
Beta Was this translation helpful? Give feedback.
-
For me it's just ugly. Usage of a disposable object looks really good and safe only if you assign it to a local variable right into the using statement. |
Beta Was this translation helpful? Give feedback.
-
Why? |
Beta Was this translation helpful? Give feedback.
-
Because you cannot use a variable defined into |
Beta Was this translation helpful? Give feedback.
-
This is already legal. You may have to fight with the autoformatter, though. I haven't tried in VS. If that's the case you could post an issue in the Roslyn repo to have the formatter respect it. foreach (var adapter in stuffAdapterSeq) using (adapter)
{
// get stuff
} |
Beta Was this translation helpful? Give feedback.
-
This is a good point. I can live with this syntax even if I believe my syntax is better :) I want to say that from the very beginning |
Beta Was this translation helpful? Give feedback.
-
I disagree. It's about readability and maintainability. Good code isn't about how few keystrokes it takes to write, but about how easy it is for someone who's never seen it before to understand and fix it. Sometimes that's the same as "shorter" (by reducing code clutter and boilerplate), but sometimes it isn't. In this case, you're introducing syntax that every C# developer will have to learn, in order to make a rare case a few characters terser. You're also IMO making it less maintainable, as it's less obvious to someone skimming over the code that the loop variable is being disposed. Remember that disposal in particular is something that developers need to keep track of by hand, and it's often not obvious when something is not being disposed when it should, or is being disposed twice. Making this information harder to find is not going to help. |
Beta Was this translation helpful? Give feedback.
-
While I agree with this, I believe that if the syntax for expressing a certain operation can be easily made more elegant, it should be, as it would not necessarily hurt readability as long as the language is understood, but would make the code more clean and faster to write. An example of this in practice is the
I find the use of this argument odd, as the |
Beta Was this translation helpful? Give feedback.
-
Old issue, but want to add foreach (var adapter in stuffAdapterSeq) using (adapter)
{
// get stuff
} and foreach (var adapter in stuffAdapterSeq)
{
using (adapter)
{
// get stuff
}
} are not ok when |
Beta Was this translation helpful? Give feedback.
-
@johnkellyoxford You can. That's already legal today in C#
This seems to be a separate request. |
Beta Was this translation helpful? Give feedback.
-
Yes, you can do it. But it copies, which will often yield unexpected results when used with a value type |
Beta Was this translation helpful? Give feedback.
-
@johnkellyoxford What copy are you worried about, exactly? The |
Beta Was this translation helpful? Give feedback.
-
I just wrote a |
Beta Was this translation helpful? Give feedback.
-
It looks like the issue is quite old, but I just encountered a problem described by the author. foreach(using var item in collection)
{/* working with disposable item */} to something like this (and also unwrapping using(var enumer = collection.GetEnumerator())
while(enumer.MoveNext())
using(var item = enumer.Current)
{/* working with disposable item */} This allows for all the optimizations to happen accordingly, and also gives a hint to the compiler about resource usage within loop body. However, the downside of this issue is that the collection item can support await foreach(await using var item in collection)
{/* get item asynchronously, do work and dispose asynchronously */} |
Beta Was this translation helpful? Give feedback.
-
I am in favor of a The existing suggested syntax The visual studio formatter gets confused by it and indents the braces 'incorrectly'. //before format document
foreach (var container in site.GetFileContainers()) using (container)
{
//stuff
} //after format document
foreach (var container in site.GetFileContainers()) using (container)
{
//stuff
} |
Beta Was this translation helpful? Give feedback.
-
@AlgorithmsAreCool if you want to see a formatting change, please suggest it on dotnet/roslyn. |
Beta Was this translation helpful? Give feedback.
-
@333fred |
Beta Was this translation helpful? Give feedback.
-
not the best justification in the world... 😉 |
Beta Was this translation helpful? Give feedback.
-
That's not a language change. Even if the language supports something, the formatter only changes by fixing up the formatter. |
Beta Was this translation helpful? Give feedback.
-
I seem to making terrible comments all over the place today :/ @CyrusNajmabadi This 'existing' syntax ( Edit: Re-reading the thread shows that Halofour made this same observation months ago. ☹ |
Beta Was this translation helpful? Give feedback.
-
So fix them. :-) It's roughly 1000x-10000x cheaper than updating the language. (Note: that's not an exaggeration on costs). |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi But it boils down to this for me, Maybe it's fluff, maybe it's a little usability gap, but it surprised me. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Description
What I have
What I want to have
This should also work with IAsyncEnumerable and IAsyncDisposable:
Usability
First case
I have an async stream of
TextReader
s which I want to deserialize and put to another async stream.TextReader is an abstract class so I cannot do it other way and keep polymorphism.
Second case
I have to do an sql query and return result as an async stream of rows.
— You're ignorant! You're going to allocate a new instance of
ISqlRowReader
for every row in result! Why don't you implement some interface kind ofSystem.Data.IDataReader
with a method kind ofValueTask ReadAsync()
and iterate query result without allocating new objects?You're right. But I can do the same using
IAsyncEnumerable
and polled objects:Now I have only one extra allocation but I keep using
await foreach
which is so fluent and readable!So
There are the patterns required to enumerate and stream the disposable objects and it would be great to iterate them in a fluent way. My cases seems very common for me as a backend programmer. "using" statement as a part of "foreach" will keep
IAsyncEnumerable
as a "chosen one" abstraction for an async streams.Beta Was this translation helpful? Give feedback.
All reactions