此时我已经超出了我的范围。我正在尝试创建一个类似的界面 此
type IFetchData =
abstract FetchData: string -> seq<'a>
上面的声明是有效的(并编译)但是当我去使用它时,我得到一个编译时错误。这个表达式预计会有'a但是这里有类型'我正在尝试返回的类型“即seq。
我的示例用法如下所示:
type SampleFetchData() =
interface IFetchData with
member self.FetchData str =
seq {
for letter in str do
yield letter // compile error here
}
我不确定我做错了什么。我想做的就是允许接口实现者能够编写任何返回通用序列的函数seq<string>
,seq<int>
,seq<record type here>
,seq<union type here>
等
有人能告诉我我在这里缺少什么吗?
感谢。
答案 0 :(得分:4)
如果您使用Reflection加载接口实现,那么使用它将非常困难。问题是你得到了obj
类型的对象。您知道它为某些IFetchData<'T>
实施了'T
,但在静态情况下,您不知道哪个'T
。这是一个问题,因为您无法将对象强制转换为任何更具体的类型 - 如果您尝试使用IFetchData<obj>
,它将无效,因为您无法将IFetchData<int>
转换为{类型。
我建议使用非通用接口,这是非常常见的.NET模式:
type IFetchDataUntyped =
abstract FetchData : string -> System.Collections.IEnumerable
type IFetchData<'T> =
inherit IFetchDataUntyped
abstract FetchData : string -> seq<'T>
使用Reflection加载实现时,可以将对象强制转换为IFetchDataUntyped
并以相当合理的方式使用它(如果您知道的话,使用Seq.cast
将序列转换为更具体的类型元素类型)。
根据您的应用程序,您可能只需将FetchData
方法设为泛型方法并保持接口非通用。然后,您可以将动态加载的对象强制转换为接口并调用该方法。但是,这会改变设计(因为该方法必须适用于它作为类型参数获取的任何类型):
type IFetchData =
abstract FetchData<'T> : string -> seq<'T> // Note: Generic parameter here!
答案 1 :(得分:3)
您需要执行类似
的操作type IFetchData<'a> =
abstract FetchData: string -> seq<'a>
type SampleFetchData() =
interface IFetchData<char> with
member self.FetchData str =
seq {
for letter in str do
yield letter
}
即。接口需要通用。如果要避免泛型,可以使用一些内联约束,而不是接口
编辑:内联魔术版
let inline Fetchdata string obj=
(^a: (member FetchData: string -> seq<'b> )(obj, string))
type SampleFetchData() =
member self.FetchData str =
seq {
for letter in str do
yield letter
}
Fetchdata "hello" (new SampleFetchData())