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?
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;
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With