Reputation: 541
I have a class Foo which contains a pointer to unmanaged memory from C dll. It implements IDisposable to free unmanaged memory using C dll and some other functionality with that ptr using dll.
public unsafe class Foo : IDisposable {
void* ptr;
internal Foo() {
/* initialize ptr from C dll */
};
public int getInfo() {
/* return info from ptr using dll */
}
public Dispose() {
/* free ptr using C dll */
}
}
Also I have a factory which returns an exemplar of Foo object:
public unsafe class FooFactory {
public Foo createFoo() {
return new Foo();
}
}
Finally I have a function which takes Foo as argument, processes it and returns:
public Foo process(Foo f) {
/* do some stuff with f */
return f;
}
All I want to do is to prevent user from creating Foo object, storing it in a variable and passing that variable to a process
with saving result to another variable, because it may be unsafe in such example:
Foo f2 = null;
using (var f1 = FooFactory.createFoo()) {
// inside one can work with f1 and f2
f2 = process(f1);
}
// but outside f1's ptr is already destroyed in C dll and f2 can not use it
f2.getInfo();
I want them use only on of these approaches, as they are safe:
using var f1 = FooFactory.createFoo();
f1 = process(f1);
// or
using var f1 = process(FooFactory.createFoo());
In C++ I can do it using std::unique_ptr as it is not copyable. Is there any way to do it in C#?
Upvotes: 0
Views: 136
Reputation: 416039
Nothing comes to mind to exactly match that pattern.
Instead, I would expect the Foo
type to raise an ObjectDisposedException
if I tried to use f2
after leaving the using
block. Checking status and throwing that exception might be one of the first responsibilities of the getInfo()
(and similar) methods. The using
pattern is pretty-strongly engrained among C# developers, where no one writing this code would be surprised by this behavior.
This is also one of the rare cases where you may want to implement a finalizer for the C# type.
Upvotes: 2
Reputation: 112512
You can't forbid that, but you can make the Foo
class safer by adding some code:
public unsafe class Foo : IDisposable
{
void* ptr;
internal Foo()
{
/* initialize ptr from C dll */
}
public int getInfo()
{
if (ptr is null) { // <==== test whether ptr is still valid!
return 0; // or throw an exception.
}
/* return info from ptr using dll */
}
public void Dispose()
{
/* free ptr using C dll */
ptr = null; // <==== set ptr = null when disposed!
}
}
Upvotes: 1