2010-06-13 88 views
2

我正在翻译一个API从C到C#,其中一个函数分配了一些相关的对象,其中一些是可选的。 C版本接受它用于返回整数处理的对象几个指针参数,调用者可以通过NULL对于一些指针,以避免分配这些对象:在C#中模拟可选的“out”参数的模式?

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

initialize(&mainObj, &subObj, NULL); 

对于C#版本,很明显的翻译将使用out参数,而不是指针:

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

...但是这叶无道,以指示哪些对象是不需要的。有没有任何C#API的着名例子可以做类似的事情,我可以模仿?如果没有,有什么建议吗?

回答

3

那么,你不应该使用int作为对象 - 它们应该是引用,即out SomeMainType mainObj, out SomSubType subObj。这样做,你可以使用重载,但这将是不明智的。

更好的方法是用3个对象返回一些东西 - 一个自定义类型,或者在.NET 4.0中可能是一个元组。

喜欢的东西:

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

重读它,它看起来像调用者也在传递数据(哪怕只是空/不为空),所以out从来没有正确的选项。也许一个标志枚举?

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

,并呼吁:

var result = Initialize(InitializeOptions.Main | InitializeOptions.Sub); 
var main = result.MainObject; 
var sub = result.SubObject; 
2

最接近的翻译会使用refIntPtr

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

和不需要的值指定IntPtr.Zero

但是对于我来说,问题出现的原因是为什么你想要类似的API关闭,除非你试图找出一个P/Invoke签名。假设mainObj有两个子对象像

public static MainObjectType Initialize(bool initSubObj, bool initAnotherSubObj) 

访问引用似乎是一个更清洁的解决方案给我。在.NET 4中,你甚至可以使布尔参数为可选的,或者在.NET 4之前用重载模拟这个参数。如果没有对子对象的可访问引用,你可以返回一个容纳引用的简单容器类型。

0

可以提供不拿出参数的方法的重载和调用,它的过载:

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

但是,马克的建议,你应该考虑使用更面向对象的方法。 ..

+0

不幸的是我需要避免分配不需要的对象:第一,因为一旦创建对象时屏幕上会显示一些对象,第二,因为这是非托管库的接口,所以我分配的任何对象最终需要明确地解放。 (非托管部分也是为什么对象使用句柄而不是.NET类型引用的原因。) – 2010-06-13 18:14:45