如何为泛型类型编写扩展方法,其中一个类型变量必须是字符串?

时间:2017-03-17 21:33:50

标签: generics f# extension-methods

特别是,我想为此类型编写扩展方法:

type Frame<'TRowKey, string when 'TRowKey : equality> with
  member frame.someMethod =
    // code

使用该代码,我收到此错误:

  

类型名称中的意外标识符。预期的中缀运算符,引号或其他标记。

string替换为String会得到相同的结果。

原始类型是Deedle库中的Frame<'TRowKey, 'TColumnKey (requires equality and equality)>

2 个答案:

答案 0 :(得分:5)

@Gustavo彻底解答了如何使用扩展方法。但是如果你没有特别强烈的理由将它作为一种扩展方法(比如C#interop),你可能会选择一个简单的函数:

type Frame<'row, 'col> = { row: 'row; col: 'col }

module Frame = 
    let restricted (frame: Frame<'row, string>) = frame

Frame.restricted { row = 3; col = "test" } // compiles
Frame.restricted { row = 3; col = 5 }      // doesn't

我在编写F#时只考虑更简洁的方法 - 只有代码 - 当它们作为类型的内在部分不具有意义时,let-bound函数优于方法,并且从属性中减少噪音。

答案 1 :(得分:2)

我没有Deedle来测试这段代码但你应该使用.NET扩展方法:

open System

[<Runtime.CompilerServices.Extension>]
module Extensions =
    [<Runtime.CompilerServices.Extension>]
    let someMethod<'TRowKey when 'TRowKey : equality> (frame :Frame<'TRowKey, string>) = // body

这与scrwtp称之为“惯用方式”的方式相同。 (我不想讨论有关idomaticity的问题)但同时它也可以作为扩展方法从C#开始。

如果要从F#和扩展名中使用它,必须将其声明为类型:

[<Runtime.CompilerServices.Extension>]
type Extensions =
    [<Runtime.CompilerServices.Extension>]
    static member someMethod<'TRowKey when 'TRowKey : equality> (frame :Frame<'TRowKey, string>) = // body

所以现在你可以输入row.,如果第二个参数是一个字符串,intellisense将只显示扩展名。