Reputation: 91
It is beyond me at this point. I'm trying to create an interface that looks something like this.
type IFetchData =
abstract FetchData: string -> seq<'a>
The above declaration is valid (and compiles) but when I go to use it I get a compile time error. This expression was expected to have type 'a but here has type "what I'm currently trying to return" i.e. seq.
My example usage however looks like the following:
type SampleFetchData() =
interface IFetchData with
member self.FetchData str =
seq {
for letter in str do
yield letter // compile error here
}
I'm not sure what I'm doing wrong. All I'd like to do is allow the interface implementer to be able to write any function that returns a generic sequence either seq<string>
,seq<int>
,seq<record type here>
, seq<union type here>
, etc.
Can someone tell me what I'm missing here?
Thanks.
Upvotes: 3
Views: 526
Reputation: 243126
If you're loading the interface implementation using Reflection, then it is going to be quite difficult to work with it. The problem is that you get an object of type obj
. You know that it implements IFetchData<'T>
for some 'T
, but statically, you don't know for which 'T
. This is a problem because you can't cast the object to any more specific type - if you tried using IFetchData<obj>
, it wouldn't work because you can't cast, for example, IFetchData<int>
to that type.
I would recommend using a non-generic interface, which is quite common .NET pattern:
type IFetchDataUntyped =
abstract FetchData : string -> System.Collections.IEnumerable
type IFetchData<'T> =
inherit IFetchDataUntyped
abstract FetchData : string -> seq<'T>
When you load an implementation using Reflection, you can cast the object to IFetchDataUntyped
and work with it in a fairly reasonable way (using Seq.cast
to convert the sequence to a more specific type if you know the element type).
Depending on your application, you may also just make the FetchData
method a generic method and keep the interface non-generic. Then you could cast dynamically loaded objects to the interface and invoke the method. However, this changes the design (because the method has to work for any type it gets as a type parameter):
type IFetchData =
abstract FetchData<'T> : string -> seq<'T> // Note: Generic parameter here!
Upvotes: 4
Reputation: 25526
You need to do something like
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
}
i.e. the interface needs to be made generic. If you want to avoid the genericness you could use some inline constraints, rather than an interface
EDIT: Inline magic version
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())
Upvotes: 3