-
Notifications
You must be signed in to change notification settings - Fork 1k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
tuples and disposable objects #6620
Comments
The tuple itself wouldn't be disposable. As of now I doubt that the |
This is an interesting problem. At first glance, tuples should be
However, tuples don't really contain instances of disposable types, just like But providing a convenient way to handle tuples with disposable content would simplify a lot of use cases. Therefore I think using (let (status, bmp) = TryCaptureImage()) {
...
} ///bmp is disposed of This way a tuple is deconstructed ASAP and you are dealing with raw values. If you really need to store the tuple, then you handle it manually, like you would handle a |
Do the current tuple proposal/design also include indexed locations? We could do something like using ((var (a, b, c) = ThisMethodReturnsATuple()).Item2) { ... }
// simplified if return value isn't used in the block
using (ThisMethodReturnsATuple().Item2) { ... } or perhaps using ((var (a, b, c) = ThisMethodReturnsATuple())[1]) { ... }
// simplified if return value isn't used in the block
using (ThisMethodReturnsATuple()[1]) { ... } Downside, that is limited to a single item within the tuple. |
Possible new syntax which allows disposing of more than one item within the tuple: using (a, b) in (var (a, b, c) = ThisMethodReturnsATuple())
{
...
} using b in (var (a, b, c) = ThisMethodReturnsATuple())
{
...
} |
After sleeping on this, what's wrong with existing language support plus tuple destructuring? let (status, bmp) = TryCaptureImage();
using (bmp) {
...
} |
I think one should be able to implement extension<T, U> (T, U) : IDisposable where T : IDisposable where U : IDisposable {
public void Dispose() {
this.Item1.Dispose();
this.Item2.Dispose();
}
} which is the same as defining an extension method (#258). static class ValueTupleExtensions {
public static Dispose<T, U>(this (T, U) @this) where T : IDisposable where U : IDisposable {
@this.Item1.Dispose();
@this.Item2.Dispose();
}
} |
Although, if just one of the items was |
@alrz It could be used for multiple as well, albeit a bit clunky: let (status, bmp) = TryCaptureImage();
using (status)
using (bmp)
{
...
} I would prefer a way to combine them in one line. |
I think making tuples to implement IDisposable could be a very fragile approach, considering that they are structs. It would be too easy to dispose a copy. What might be a more robust approach is teach "using" to decompose tuples into nested guarded blocks. The issue with that approach would be finding a clever syntax for introducing tuple fields as standalone variables inside using. using (a: Foo(), b: Bar())
{
a.Do();
b.Work();
} emitted as using (var a = Foo())
{
using (var b = Bar())
{
a.Do();
b.Work();
}
} |
C# could be modified to allow the inline C++ style RAII syntax: if (asdf) {
something1();
using T foo = whatever1();
using bar = whatever2();
something2();
// bar gets disposed here
// foo gets disposed here
} in addition to the current lisp style nesting syntax: if (asdf) {
something1();
using (T foo = whatever1()) {
using (var bar = whatever2()) {
something2();
// bar gets disposed here
}
// foo gets disposed here
}
} If these changes were made then tuple element disposal falls out naturally with this syntax: let (using a, using b) = Foo(); |
Why go to all the trouble? Just deconstruct the tuple and use the items in any way you see fit. If it's using them on a |
Sorry to ask, given this got a milestone, what is the conclusion/action that is going to be implemented? Since "using" is a compiler magic, and most of time people would call it like this:
It is very reasonable to expect the same magic can dispose tuple returned by method call, it fits us average programmers' understanding of "using". One of the reason could forcing us to use tuple e.g. Having multiple lines to work around this just looks ugly when "using" is already a magic, half done magic is ugly. |
@xied75 With our release candidate date closing in fast, this (or some flavor for it) isn't planned for C# 7.0. |
Hi, is there any update on disposable tuples? After reading the comments above (and after using tuples a lot in code) I think tuples should be disposable -- at least if a containing element is disposable. One solution could be (I don't know whether compatible with CLR): If the tuple has one or more member type that implements This would mean (edge case) that Tuple<object, Stream> is IDisposable and Stream will be disposed, object not. One could argue that disposing object via Regarding comments that say one could easily workaround by explicitely calling Dispose on tuple parts or even use some extension method: This does not solve use cases where you pass the tuple to some code where it's relevant whether the type implements IDisposable. If you build generic code that creates objects and removes them later that code probably should check whether the created object is IDisposable because the generic code @orthoxerox pointed out that it all depends on whether Tuple If you see tuples as syntactic replacement for multiple single variables (grouping of variables) then it would be quite useful to have this IDisposable (at least if one or more items are...) Tuples are most useful this way and C# is designed to support this by it's syntax. E.g. tuples are a great way to get rid of Currently I cannot use tuples for use cases above (generic code) but will have to create custom types. As ValueTuple<> is sealed I cannot easily build my own tuple type on top of it that at least would be IDisposable on runtime, either. |
Nope :)
This is true of any code that checks for some interface, but you want to pass a tuple of values to. In this case, tuples are not the right mechanism, and you should build your own type that can properly implement whatever interfaces are relevant to you, and forward them appropriately to any elements it holds. As @orthoxerox said:
|
@CyrusNajmabadi: I don't agree since tuples have more in common with function arguments than with lists. Currently you cannot have generic code that handles lifetimes based on IDisposable correct when using factory methods that have more then one return value -- without creating a custom class. Some generic method:
You could call this:
which works fine now. I would like to be able to call the same generic function with tuple this way, too:
This currently does not work because BTW: In some future version of C# where #258 is reality this could be just:
This is of course just a small example which can easily replaced by other code. It's just to show the principle. |
Even if C# were to treat tuples of |
@StefanBertels, the purpose of tuples is to represent a list of values somewhat related and unrelated. They do not represent an entity. You can look at tuples as something like this:
If the semantics of the above method is the same as If the set of values has a meaning of its own (like being disposable) than you should create a specific type for that. |
We're currently prototype "pattern-based Note a small subtlety: such |
@HaloFour Can you give more details? I currently don't see a reason why there cannot be some DisposableValueTuple<> that works like ValueTuple<> -- with similar direct compiler support. @paulomorgado: Your TryParse example doesn't show whether tuple disposability would be good/bad as neither bool nor int implement IDisposable / cannot be disposed at all. (BTW: Better return value would be something like Option here.) We can always build specific types, but ValueTuple reduces boilerplate code and gives syntactic sugar for simple use cases. @jcouv Thanks for the link. This will only help with |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Hi,
I'm following the discussion about tuples, and I have a question about this.
Often I have methods the return disposable objects (the most common is a ef or ado.net db connection, and to be sure that are correctly dispose I use using (...
Now, if one of the members of the tuple is an object like this, how can I handle its disposal in a proper way? For example I can have a method that returns both an ado.net sqlconnection and the related transaction object, because I want to encapsulate the creation procedure.
The text was updated successfully, but these errors were encountered: