elo
elo

Reputation: 541

Forbid to copy a variable

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

Answers (2)

Joel Coehoorn
Joel Coehoorn

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

Olivier Jacot-Descombes
Olivier Jacot-Descombes

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

Related Questions