views:

61

answers:

3

I'm translating an API from C to C#, and one of the functions allocates a number of related objects, some of which are optional. The C version accepts several pointer parameters which are used to return integer handles to the objects, and the caller can pass NULL for some of the pointers to avoid allocating those objects:

void initialize(int *mainObjPtr, int *subObjPtr, int *anotherSubObjPtr);

initialize(&mainObj, &subObj, NULL);

For the C# version, the obvious translation would use out parameters instead of pointers:

public static void Initialize(out int mainObj, out int subObj,
    out int anotherSubObj);

... but this leaves no way to indicate which objects are unwanted. Are there any well-known examples of C# APIs doing something similar that I could imitate? If not, any suggestions?

+2  A: 

Well, you shouldn't be using int for the objects anyway - they should be references, i.e. out SomeMainType mainObj, out SomSubType subObj. That done, you can then use overloads, but this would be ungainly.

A better approach would be to return something with the 3 objects - a custom type, or in .NET 4.0 maybe a tuple.

Something like:

class InitializeResult {
    public SomeMainType MainObject {get;set;}
    public SomeSubType SubObject {get;set;}
    ...
}
public static InitializeResult Initialize() {...}

Re-reading it, it looks like the caller is also passing data in (even if only null / not-null), so out was never the right option. Maybe a flags enum?

[Flags]
public enum InitializeOptions {
    None = 0, Main = 1, Sub = 2, Foo = 4, Bar = 8, ..
}

and call:

var result = Initialize(InitializeOptions.Main | InitializeOptions.Sub);
var main = result.MainObject;
var sub = result.SubObject;
Marc Gravell
+2  A: 

The closest translation would be using ref and IntPtr

public static void Initialize(ref IntPtr mainObj, ref IntPtr subObj,
ref IntPtr anotherSubObj)

and specifying IntPtr.Zero for unwanted values.

But for me the question arises why you want to resemble the API that close unless you are trying to figure out a P/Invoke signature. Assuming mainObj has accessible references to both sub object something like

public static MainObjectType Initialize(bool initSubObj, bool initAnotherSubObj)

appears to be a much cleaner solution to me. In .NET 4 you can even make the boolean arguments optional or simulate this with overloads in pre .NET 4. If there are no accessible references to the sub objects you could return a simple container type holding the references.

Daniel Brückner
A: 

You can provide overloads of the method that don't take out parameters, and call the overload that does :

public static void Initialize()
{
    int mainObj;
    int subObj;
    int anotherSubObj;
    Initialize(out mainObj, out subObj, out anotherSubObj);
    // discard values of out parameters...
}

public static void Initialize(out int mainObj, out int subObj, out int anotherSubObj)
{
    // Whatever...
}

But as suggested by Marc, you should probably consider using a more object oriented approach...

Thomas Levesque
Unfortunately I need to avoid allocating the unwanted objects at all: first because some of the objects will be visible on screen as soon as they're created, and second because this is an interface for an unmanaged library, so anything I allocate will eventually need to be freed explicitly. (The unmanaged part is also why the objects are referred to with handles rather than .NET types.)
Jesse McGrew