元帅 bool return 作为自定义 Return<bool>
Marshal bool return as custom Return<bool>
我目前正在 .Net 中包装 Un4seen BASS 音频库
BASS 函数 returning bool
值,需要检查 LastError
以了解如果 returned 为 false 时发生的错误。
所以我实现了一个 Return<T>
class 使其面向对象:
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 一个 Return<bool>
以便用户可以轻松地以面向对象的方式检查 ErrorCode
。
现在,您可能会说我创建了另一个方法,例如:
// bool implicitly converts to Return<bool>
public static Return<bool> StreamFree2(int Handle) => StreamFree(Handle)
但是,问题是已经有数以千计的 DllImport 并且对所有这些都执行此操作将是一场噩梦。
所以,我尝试了:
[DllImport(DllName, EntryPoint = "BASS_StreamFree")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Return<bool> StreamFree(int Handle);
它编译了,但根本不起作用。
任何人都可以指出我错在哪里或者这样的事情是否可能。
提前致谢。
如果不 编写包装函数,就无法做到这一点。您不能简单地更改函数的 return 类型。编组器将无法自动创建新的 Return<T>
对象。您最后一次声明尝试告诉编组器函数 return 是一个 BOOL
,但该函数未声明为 return 一个 BOOL
。显然那是行不通的;当检测到不匹配时,它在运行时失败。
可能还有其他问题。我不知道 BASS 库实际运行的是什么类型 return,但如果它是 bool
,那么 UnmanagedType.Bool
就是错误的类型。你实际上想要UnmanagedType.U1
。 UnmanagedType.Bool
指的是4字节的BOOL
类型,其实就是一个整数。 UnmanagedType.U1
指C++的1字节bool
类型。
更一般地说,我认为您的 "object-oriented" 方法不会提供任何真正的优势。当然,您会 returning 一个对象,但是您编写的客户端代码看起来不会有任何不同,因为您仍然需要每次检查错误代码。
当库函数 return 出错时,一个优雅的、符合 .NET 的设计会抛出异常。然后该异常(BassException
或其他)将包装错误代码。当然,这将需要为每个库函数编写包装函数,但至少完成后会有一些回报。考虑使用工具自动生成此类函数。
我目前正在 .Net 中包装 Un4seen BASS 音频库
BASS 函数 returning bool
值,需要检查 LastError
以了解如果 returned 为 false 时发生的错误。
所以我实现了一个 Return<T>
class 使其面向对象:
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 一个 Return<bool>
以便用户可以轻松地以面向对象的方式检查 ErrorCode
。
现在,您可能会说我创建了另一个方法,例如:
// bool implicitly converts to Return<bool>
public static Return<bool> StreamFree2(int Handle) => StreamFree(Handle)
但是,问题是已经有数以千计的 DllImport 并且对所有这些都执行此操作将是一场噩梦。
所以,我尝试了:
[DllImport(DllName, EntryPoint = "BASS_StreamFree")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Return<bool> StreamFree(int Handle);
它编译了,但根本不起作用。
任何人都可以指出我错在哪里或者这样的事情是否可能。
提前致谢。
如果不 编写包装函数,就无法做到这一点。您不能简单地更改函数的 return 类型。编组器将无法自动创建新的 Return<T>
对象。您最后一次声明尝试告诉编组器函数 return 是一个 BOOL
,但该函数未声明为 return 一个 BOOL
。显然那是行不通的;当检测到不匹配时,它在运行时失败。
可能还有其他问题。我不知道 BASS 库实际运行的是什么类型 return,但如果它是 bool
,那么 UnmanagedType.Bool
就是错误的类型。你实际上想要UnmanagedType.U1
。 UnmanagedType.Bool
指的是4字节的BOOL
类型,其实就是一个整数。 UnmanagedType.U1
指C++的1字节bool
类型。
更一般地说,我认为您的 "object-oriented" 方法不会提供任何真正的优势。当然,您会 returning 一个对象,但是您编写的客户端代码看起来不会有任何不同,因为您仍然需要每次检查错误代码。
当库函数 return 出错时,一个优雅的、符合 .NET 的设计会抛出异常。然后该异常(BassException
或其他)将包装错误代码。当然,这将需要为每个库函数编写包装函数,但至少完成后会有一些回报。考虑使用工具自动生成此类函数。