简体   繁体   English

具有实现接口的通用类型参数的不同类型的拆箱实例

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM