[英]Unboxing Instances of Different Types with a Generic Type Parameter that Implements an Interface
I am working on an abstraction for a variation on a key-value store style API where I have the following interfaces (simplified for clarity). 我正在研究键值存储样式API的变体的抽象,其中我有以下接口(为简洁起见而简化)。
type IValue =
abstract member Id: int64
type IKey<'value when 'value :> IValue> = interface end
type IKeyGenerator<'value, 'key when 'value :> IValue and 'key :> IKey<'value>> =
abstract member Generate: 'value -> 'key
type IKeyValueStore<'value when 'value :> IValue> =
abstract member Store: 'value -> unit
abstract member Get: int64 -> 'value option
abstract member Find<'key when 'key :> IKey<'value>> : 'key -> 'value option
Basically, each value can be looked up by multiple keys, and the keys for each value are generated by IKeyGenerator
s. 基本上,每个值都可以通过多个键查找,每个值的键由IKeyGenerator
生成。 When I call Store
on the IKeyValueStore
, I want to find all the key generators for the given value, run each of them, and store each key for the value so it can then be retrieved by any of those keys. 当我在IKeyValueStore
上调用Store
时,我想找到给定值的所有密钥生成器,运行它们中的每一个, IKeyValueStore
每个键,以便可以通过任何这些键检索它。
My problem is that, while I can reflectively discover all implementations of IKeyGenerator
that have a 'value
type parameter that matches the 'value
type for this IKeyValueStore
, I can't safely unbox them to a consistent type. 我的问题是,虽然我可以反思地发现具有'value
类型参数匹配此IKeyValueStore
'value
类型的IKeyGenerator
所有实现,但我无法安全地将它们拆分为一致类型。 I tried unboxing them all to IKeyGenerator<'value, IKey<'value>>
, but this doesn't work if the concrete implementations don't explicitly implement the interface that way. 我尝试将它们全部拆箱到IKeyGenerator<'value, IKey<'value>>
,但如果具体实现没有以这种方式显式实现接口,则这不起作用。 If they implement the interface referring to a specific implementation of IKey
, the unboxing fails. 如果它们实现了引用IKey
的特定实现的IKey
,则取消装箱将失败。
I then tried introducing a simplified IKeyGenerator<'value>
interface that defined the Generate
method as simply returning IKey<'value>
instead of 'key :> IKey<'value>
, which solves the problem with unboxing all the implementations, but I then run into problems downstream with not knowing the actual type of the key (for example, in order to do the Find
when there are multiple possible keys for this value). 然后我尝试引入一个简化的IKeyGenerator<'value>
接口,将Generate
方法定义为简单地返回IKey<'value>
而不是'key :> IKey<'value>
,这解决了拆箱所有实现的问题,但我接着在不知道密钥的实际类型的情况下遇到下游问题(例如,为了在此值有多个可能的密钥时执行Find
)。
Is there some way I can safely obtain a list of IKeyGenerator
instances for different IKey
implementations, provided that they all implement IKey<'value>
for the same type of value? 有没有什么方法可以安全地获取不同IKey
实现的IKeyGenerator
实例列表,前提是它们都为相同类型的值实现了IKey<'value>
?
I would recommend a two-tier implementation of the key generators: a base class that implements IKeyGenerator
, but itself has more concrete type parameters, constrained in the way you have there: 我建议使用密钥生成器的两层实现:一个实现IKeyGenerator
的基类,但它本身有更多具体的类型参数,受限于你在那里的方式:
type IKeyGenerator<'value when 'value :> IValue> =
abstract member Generate: 'value -> IKey<'value>
[<AbstractClass>]
type KeyGeneratorBase<'value, 'key when 'value :> IValue and 'key :> IKey<'value>> =
abstract member Generate: 'value -> 'key
interface IKeyGenerator<'value> with
override this.Generate v = this.Generate v :> _
Then have specific implementations inherit from KeyGeneratorBase
. 然后让特定的实现继承自KeyGeneratorBase
。
This way, the implementations can have their concrete types to work with, and the consumer will have the narrow types that it expects. 这样,实现可以使用它们的具体类型,并且消费者将具有它期望的窄类型。
Or, alternatively (and I much prefer this way), have a function to create IKeyGenerator
s: 或者,或者(我更喜欢这种方式),有一个创建IKeyGenerator
的函数:
let mkKeyGenerator<'value, 'key when 'value :> IValue and 'key :> IKey<'value>> (gen : 'value -> 'key) =
{ new IKeyGenerator<_> with
member this.Generate v = gen v :> _
}
PS I know this is not what you asked for, but I must warn against excessive use of reflection and classes. PS我知道这不是你要求的,但我必须警告不要过度使用反射和类。 This never ends well. 这永远不会结束。 Consider a more functional, idiomatic approach. 考虑一种更实用,惯用的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.