如何在 F# 中使用属性注释接口 属性 get 和 set
How to annotate interface property get and set with attributes in F#
如何将以下COM接口转换为F#?我不知道如何注释 属性 的 get
和 set
。
此外,对于 COM 互操作,我是否需要用 DispId
注释 属性 本身及其 get
?
[ComImport, TypeLibType((short)0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")]
private interface IWshShortcut
{
[DispId(0)]
string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; }
[DispId(0x3e8)]
string Arguments { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] set; }
[DispId(0x3ec)]
string RelativePath { [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ec)] set; }
[DispId(0x3ee)]
int WindowStyle { [DispId(0x3ee)] get; [param: In] [DispId(0x3ee)] set; }
[DispId(0x3ef)]
string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] set; }
[TypeLibFunc((short)0x40), DispId(0x7d0)]
void Load([In, MarshalAs(UnmanagedType.BStr)] string PathLink);
[DispId(0x7d1)]
void Save();
}
这是一个正确的翻译,虽然不是字面意思:
[<ComImport; Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"); TypeLibType(0x1040s)>]
type private IWshShortcut =
[<DispId(0)>]
abstract member FullName : [<MarshalAs(UnmanagedType.BStr)>] string with get
[<DispId(0x3e8)>]
abstract member Arguments : [<MarshalAs(UnmanagedType.BStr)>] string with get, set
[<DispId(0x3ec)>]
abstract member RelativePath : [<MarshalAs(UnmanagedType.BStr)>] string with set
[<DispId(0x3ee)>]
abstract member WindowStyle : int with get, set
[<DispId(0x3ef)>]
abstract member WorkingDirectory : [<MarshalAs(UnmanagedType.BStr)>] string with get, set
[<DispId(0x7d0); TypeLibFunc(0x40s)>]
abstract member Load : [<MarshalAs(UnmanagedType.BStr)>] PathLink:string -> unit
[<DispId(0x7d1)>]
abstract member Save : unit -> unit
如您所见,您不能将属性添加到 F# 中抽象 属性 的基础 getter/setter 方法,只能添加到 属性 本身,但这并不重要这个特定的界面:
- 具有
get
和 set
的字符串属性无论如何都需要相同的 MarshalAs
。
In
is the default directionality for string parameters,所以无论如何指定它都是多余的。
- 像您的 C# 代码那样将
DispId
应用于 属性 getter 是合法的但毫无意义 – 而 DispId
可以同时应用于方法和属性,并且 属性 getters 和 setter 在技术上恰好是方法,属性只对 属性 本身有影响。
N.b。因为 the CLR marshals string parameters for COM methods as BStrs by default,我们也可以省略所有 MarshalAs
指令,使它看起来更 trim(尽管不那么明确):
[<ComImport; Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"); TypeLibType(0x1040s)>]
type private IWshShortcut =
[<DispId(0)>] abstract member FullName:string with get
[<DispId(0x3e8)>] abstract member Arguments:string with get, set
[<DispId(0x3ec)>] abstract member RelativePath:string with set
[<DispId(0x3ee)>] abstract member WindowStyle:int with get, set
[<DispId(0x3ef)>] abstract member WorkingDirectory:string with get, set
[<DispId(0x7d0); TypeLibFunc(0x40s)>] abstract member Load : PathLink:string -> unit
[<DispId(0x7d1)>] abstract member Save : unit -> unit
当然,所有这些也适用于C#实现,因此可以类似地简化:
[ComImport, Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"), TypeLibType((short)0x1040)]
private interface IWshShortcut
{
[DispId(0)] string FullName { get; }
[DispId(0x3e8)] string Arguments { get; set; }
[DispId(0x3ec)] string RelativePath { set; }
[DispId(0x3ee)] int WindowStyle { get; set; }
[DispId(0x3ef)] string WorkingDirectory { get; set; }
[DispId(0x7d0), TypeLibFunc((short)0x40)] void Load(string PathLink);
[DispId(0x7d1)] void Save();
}
如何将以下COM接口转换为F#?我不知道如何注释 属性 的 get
和 set
。
此外,对于 COM 互操作,我是否需要用 DispId
注释 属性 本身及其 get
?
[ComImport, TypeLibType((short)0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")]
private interface IWshShortcut
{
[DispId(0)]
string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; }
[DispId(0x3e8)]
string Arguments { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] set; }
[DispId(0x3ec)]
string RelativePath { [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ec)] set; }
[DispId(0x3ee)]
int WindowStyle { [DispId(0x3ee)] get; [param: In] [DispId(0x3ee)] set; }
[DispId(0x3ef)]
string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] set; }
[TypeLibFunc((short)0x40), DispId(0x7d0)]
void Load([In, MarshalAs(UnmanagedType.BStr)] string PathLink);
[DispId(0x7d1)]
void Save();
}
这是一个正确的翻译,虽然不是字面意思:
[<ComImport; Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"); TypeLibType(0x1040s)>]
type private IWshShortcut =
[<DispId(0)>]
abstract member FullName : [<MarshalAs(UnmanagedType.BStr)>] string with get
[<DispId(0x3e8)>]
abstract member Arguments : [<MarshalAs(UnmanagedType.BStr)>] string with get, set
[<DispId(0x3ec)>]
abstract member RelativePath : [<MarshalAs(UnmanagedType.BStr)>] string with set
[<DispId(0x3ee)>]
abstract member WindowStyle : int with get, set
[<DispId(0x3ef)>]
abstract member WorkingDirectory : [<MarshalAs(UnmanagedType.BStr)>] string with get, set
[<DispId(0x7d0); TypeLibFunc(0x40s)>]
abstract member Load : [<MarshalAs(UnmanagedType.BStr)>] PathLink:string -> unit
[<DispId(0x7d1)>]
abstract member Save : unit -> unit
如您所见,您不能将属性添加到 F# 中抽象 属性 的基础 getter/setter 方法,只能添加到 属性 本身,但这并不重要这个特定的界面:
- 具有
get
和set
的字符串属性无论如何都需要相同的MarshalAs
。 In
is the default directionality for string parameters,所以无论如何指定它都是多余的。- 像您的 C# 代码那样将
DispId
应用于 属性 getter 是合法的但毫无意义 – 而DispId
可以同时应用于方法和属性,并且 属性 getters 和 setter 在技术上恰好是方法,属性只对 属性 本身有影响。
N.b。因为 the CLR marshals string parameters for COM methods as BStrs by default,我们也可以省略所有 MarshalAs
指令,使它看起来更 trim(尽管不那么明确):
[<ComImport; Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"); TypeLibType(0x1040s)>]
type private IWshShortcut =
[<DispId(0)>] abstract member FullName:string with get
[<DispId(0x3e8)>] abstract member Arguments:string with get, set
[<DispId(0x3ec)>] abstract member RelativePath:string with set
[<DispId(0x3ee)>] abstract member WindowStyle:int with get, set
[<DispId(0x3ef)>] abstract member WorkingDirectory:string with get, set
[<DispId(0x7d0); TypeLibFunc(0x40s)>] abstract member Load : PathLink:string -> unit
[<DispId(0x7d1)>] abstract member Save : unit -> unit
当然,所有这些也适用于C#实现,因此可以类似地简化:
[ComImport, Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"), TypeLibType((short)0x1040)]
private interface IWshShortcut
{
[DispId(0)] string FullName { get; }
[DispId(0x3e8)] string Arguments { get; set; }
[DispId(0x3ec)] string RelativePath { set; }
[DispId(0x3ee)] int WindowStyle { get; set; }
[DispId(0x3ef)] string WorkingDirectory { get; set; }
[DispId(0x7d0), TypeLibFunc((short)0x40)] void Load(string PathLink);
[DispId(0x7d1)] void Save();
}