Я работаю над абстракцией для варианта 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
По сути, каждое значение может просматриваться несколькими ключами, а ключи для каждого значения генерируются с помощью IKeyGenerator
с.Когда я вызываю Store
на IKeyValueStore
, я хочу найти все генераторы ключей для заданного значения, запустить каждый из них и сохранить каждый ключ для значения, чтобы затем его можно было извлечь любым из этих ключей.
Моя проблема в том, что, хотя я могу рефлексивно обнаружить все реализации IKeyGenerator
, которые имеют параметр типа 'value
, который соответствует типу 'value
для этого IKeyValueStore
, я не могу безопасно их распаковатьдля согласованного типа.Я попытался распаковать их все на IKeyGenerator<'value, IKey<'value>>
, но это не работает, если конкретные реализации не реализуют интерфейс явно таким образом.Если они реализуют интерфейс, ссылаясь на конкретную реализацию IKey
, распаковка завершается неудачно.
Затем я попытался ввести упрощенный интерфейс IKeyGenerator<'value>
, который определял метод Generate
как простой возврат IKey<'value>
вместо 'key :> IKey<'value>
, что решает проблему с распаковкой всех реализаций, но затем я сталкиваюсь спроблемы вниз по течению из-за незнания фактического типа ключа (например, для выполнения Find
, когда есть несколько возможных ключей для этого значения).
Можно ли как-нибудь безопасно получить список IKeyGenerator
экземпляров для различных реализаций IKey
, при условии, что все они реализуют IKey<'value>
для одного и того же типа значения?