【问题标题】:Marshal bool return as custom Return<bool>Marshal bool 返回自定义 Return<bool>
【发布时间】:2016-02-25 10:55:17
【问题描述】:

我目前正在.Net 中包装 Un4seen BASS 音频库

BASS 函数返回 bool 值,如果返回 false,则需要检查 LastError 以了解发生的错误。

所以我实现了一个Return&lt;T&gt; 类来使其面向对象:

using ManagedBass.Dynamics;

namespace ManagedBass
{
    /// <summary>
    /// Wraps a Bass Error in a function return value
    /// </summary>
    /// <typeparam name="T">The Type of the function return value</typeparam>
    public class Return<T>
    {
        public Errors ErrorCode { get; }

        Return(T Value)
        {
            ErrorCode = Bass.LastError;
            this.Value = Value;
        }

        public T Value { get; }

        public static implicit operator T(Return<T> e) => e.Value;

        public static implicit operator Return<T>(T e) => new Return<T>(e);

        public bool Success => ErrorCode == Errors.OK;
    }
}

现在是这样的方法:

[DllImport(DllName, EntryPoint = "BASS_StreamFree")]
public static extern bool StreamFree(int Handle);

我希望返回一个Return&lt;bool&gt;,以便用户可以轻松地以面向对象的方式检查ErrorCode

现在,您可能会说我创建了另一个方法,例如:

// bool implicitly converts to Return<bool>
public static Return<bool> StreamFree2(int Handle) => StreamFree(Handle)

但是,问题是已经有成千上万的 DllImports 并且为所有这些都做这将是一场噩梦。

所以,我尝试了:

[DllImport(DllName, EntryPoint = "BASS_StreamFree")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Return<bool> StreamFree(int Handle);

它编译了,但根本不工作。

谁能指出我错在哪里,或者这样的事情是否可能。

提前致谢。

【问题讨论】:

    标签: c# marshalling bass


    【解决方案1】:

    没有办法做到这一点没有编写包装函数。您不能简单地更改函数的返回类型。编组器将无法自动创建新的Return&lt;T&gt; 对象。您最后一次声明尝试告诉编组器该函数返回BOOL,但该函数未声明为返回BOOL。显然那是行不通的。当检测到不匹配时,它会在运行时失败。

    可能还有另一个问题。我不知道 BASS 库函数实际返回的是什么类型,但如果是 bool,那么 UnmanagedType.Bool 是错误的类型。你实际上想要UnmanagedType.U1UnmanagedType.Bool 指的是 4 字节的 BOOL 类型,实际上是一个整数。 UnmanagedType.U1 指的是 C++ 的 1 字节 bool 类型。

    更一般地说,我认为您的“面向对象”方法不会提供任何真正的优势。当然,您会返回一个对象,但您编写的客户端代码看起来并没有什么不同,因为您仍然必须每次都检查错误代码。

    当库函数返回错误时,优雅的、符合 .NET 的设计会引发异常。然后该异常(BassException 或其他)将包装错误代码。当然,这需要为每个库函数编写包装函数,但至少完成后会有一些回报。考虑使用工具自动生成此类函数。

    【讨论】:

    • 感谢您的全面回答。
    • BTW 有什么方法可以在每次函数调用后调用一个函数
    • 我听说过关于 CodeContracts 的类似情况。我可以用它来抛出异常吗
    • 我认为代码合同在这里没有帮助。它们允许您检查前置条件和后置条件,但它们都不会满足您的要求。不,没有一般方法可以在每次函数调用后调用函数。 CLR marshaller 具有特殊处理来返回某些不可 blittable 类型,但您无法添加对自己的支持。
    • @Mathew 我真的不知道你在这里问什么。您不能在 P/Invoke 函数签名上使用代码协定。如果你想将它们用于你的包装函数,那很好。
    猜你喜欢
    • 1970-01-01
    • 2021-11-11
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    • 2019-07-08
    • 1970-01-01
    相关资源
    最近更新 更多