Background and motivation
FileStream has obsoloted constructors that take a file handle as an IntPtr, and all of them have a ownsHandle parameter to say whether the FileStream disposal should dispose of the handle, but none of the constructors that take a SafeFileHandle have a similar parameter at all - they unconditionally dispose of the SafeFileHandle. I need to create a FileStream from a handle, but have the FileStream leave the handle open when it's disposed.
Creating a new SafeFileHandle(existingHandle.DangerousGetHandle(), ownsHandle: false) is not a solution as it does not hold on to the lifetime of the SafeFileHandle it comes from - it could be finalized while the FileStream is open. The only current solution is to create a derived type - LeaveOpenFileStream, and deriving from FileStream leaves perf on the table as it has checks whether it is a derived type or not.
API Proposal
namespace System.IO;
public partial class FileStream : Stream
{
// Existing IntPtr constructors
// [EditorBrowsable(EditorBrowsableState.Never)]
// [Obsolete("This constructor has been deprecated. Use FileStream(SafeFileHandle handle, FileAccess access) instead.")]
// public FileStream(IntPtr handle, FileAccess access);
// [EditorBrowsable(EditorBrowsableState.Never)]
// [Obsolete("This constructor has been deprecated. Use FileStream(SafeFileHandle handle, FileAccess access) and optionally make a new SafeFileHandle with ownsHandle=false if needed instead.")]
// public FileStream(IntPtr handle, FileAccess access, bool ownsHandle);
// [EditorBrowsable(EditorBrowsableState.Never)]
// [Obsolete("This constructor has been deprecated. Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) and optionally make a new SafeFileHandle with ownsHandle=false if needed instead.")]
// public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize);
// [EditorBrowsable(EditorBrowsableState.Never)]
// [Obsolete("This constructor has been deprecated. Use FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) and optionally make a new SafeFileHandle with ownsHandle=false if needed instead.")]
// public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync);
// Existing SafeFileHandle constructors
// public FileStream(SafeFileHandle handle, FileAccess access);
// public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize);
// public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync);
// Proposed constructor
public FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync, bool leaveOpen);
}
API Usage
using var fileStream = new FileStream(handle, FileAccess.Read, 4096, true, leaveOpen: true)
// ...use fileStream
Alternative Designs
As an alternative, we could create a method on SafeFileHandle that creates a new handle with a lifetime linked to the original handle - i.e. the original handle won't get finalized until the new one gets finalized too, but with ownsHandle set to false so that its disposal won't dispose of the main SafeFileHandle. The new handle would essentially just be a reference to the original one, and it could be an internal derived type.
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeFileHandle
{
public SafeFileHandle CreateNonOwnedHandle();
}
We could then use this API to create a non-owned handle to the original handle, whose disposal won't dispose of the original handle, but with no lifetime risks.
Risks
I don't know.
Background and motivation
FileStreamhas obsoloted constructors that take a file handle as anIntPtr, and all of them have aownsHandleparameter to say whether theFileStreamdisposal should dispose of the handle, but none of the constructors that take aSafeFileHandlehave a similar parameter at all - they unconditionally dispose of theSafeFileHandle. I need to create aFileStreamfrom a handle, but have theFileStreamleave the handle open when it's disposed.Creating a
new SafeFileHandle(existingHandle.DangerousGetHandle(), ownsHandle: false)is not a solution as it does not hold on to the lifetime of theSafeFileHandleit comes from - it could be finalized while theFileStreamis open. The only current solution is to create a derived type -LeaveOpenFileStream, and deriving fromFileStreamleaves perf on the table as it has checks whether it is a derived type or not.API Proposal
API Usage
Alternative Designs
As an alternative, we could create a method on
SafeFileHandlethat creates a new handle with a lifetime linked to the original handle - i.e. the original handle won't get finalized until the new one gets finalized too, but withownsHandleset to false so that its disposal won't dispose of the mainSafeFileHandle. The new handle would essentially just be a reference to the original one, and it could be an internal derived type.We could then use this API to create a non-owned handle to the original handle, whose disposal won't dispose of the original handle, but with no lifetime risks.
Risks
I don't know.