Tara McGrew
Tara McGrew

Reputation: 2027

Patterns for simulating optional "out" parameters in C#?

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?

Upvotes: 3

Views: 1439

Answers (3)

Thomas Levesque
Thomas Levesque

Reputation: 292765

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...

Upvotes: 0

Daniel Brückner
Daniel Brückner

Reputation: 59705

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.

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1064244

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;

Upvotes: 3

Related Questions