【问题标题】:Patterns for simulating optional "out" parameters in C#?在 C# 中模拟可选“out”参数的模式?
【发布时间】:2010-06-13 07:41:41
【问题描述】:

我正在将 API 从 C 转换为 C#,其中一个函数分配了许多相关对象,其中一些是可选的。 C 版本接受几个指针参数,用于返回对象的整数句柄,调用者可以为某些指针传递NULL 以避免分配这些对象:

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 示例可以做类似的事情,我可以模仿?如果没有,有什么建议吗?

【问题讨论】:

    标签: c# optional-parameters out-parameters


    【解决方案1】:

    好吧,无论如何,您都不应该将 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() {...}
    

    重新阅读,看起来调用者也在传递数据 in(即使只有 null / not-null),所以 outnever正确的选择。也许是一个标志枚举?

    [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 之前使用重载来模拟它。如果没有对子对象的可访问引用,您可以返回一个简单的容器类型来保存这些引用。

      【讨论】:

        【解决方案3】:

        您可以提供不带参数的方法的重载,并调用不带参数的重载:

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

        但正如 Marc 所建议的,您可能应该考虑使用更面向对象的方法...

        【讨论】:

        • 不幸的是,我需要完全避免分配不需要的对象:首先因为某些对象在创建后就会在屏幕上可见,其次因为这是非托管库的接口,所以我分配的任何东西最终都需要显式释放。 (非托管部分也是使用句柄而不是 .NET 类型来引用对象的原因。)
        猜你喜欢
        • 2020-12-20
        • 1970-01-01
        • 2012-07-18
        • 2011-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-05
        • 2011-10-03
        相关资源
        最近更新 更多