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?
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.
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...
精彩评论