如何使用F#中的属性来获取和设置接口属性

dim*_*ich 1 com f# c#-to-f#

如何将以下COM接口转换为F#?我无法弄清楚如何注释get和set财产.

此外,对于COM互操作,我需要标注两个属性本身及其get使用DispId?

[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();
}
Run Code Online (Sandbox Code Playgroud)

ild*_*arn 6

这是一个正确的,但不是文字的翻译:

[<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
Run Code Online (Sandbox Code Playgroud)

如您所见,您不能将属性添加到F#中的抽象属性的底层getter/setter方法,只能添加到属性本身,但这对于此特定接口无关紧要:

  • 与两个字符串属性get和set需要相同的MarshalAs两个无论如何.
  • In是字符串参数的默认方向性,因此指定它将是多余的.
  • DispId像C#代码一样应用属性getter是合法的但没有意义 - 虽然DispId可以应用于方法和属性,而属性getter和setter在技术上恰好是方法,属性只对属性本身有影响.

Nb是因为CLR默认将COM方法的字符串参数编组为BStrs,我们也可以省略所有MarshalAs指令并使其看起来更加微调(尽管不那么明确):

[<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
Run Code Online (Sandbox Code Playgroud)

当然,所有这些都适用于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();
}
Run Code Online (Sandbox Code Playgroud)

  • 尽管有文档,对于具体的属性 `[&lt;A&gt;]member __.P with get() = ...` 将属性放在属性上,而不是 getter。然而,`member __.P with [&lt;A&gt;] get ... and [&lt;B&gt;] set ...` 似乎做了想要的事情。但是,我找不到抽象属性的任何类似物。可能值得在编译器和/或文档存储库上提交错误。 (2认同)