#generics #casting #f#
Вопрос:
Я пытаюсь использовать TypeSharp. До сих пор мне приходилось использовать shapeof<'T>
только следующим образом:
type AwsConfig = {
AccessKeyId : string
DefaultRegion : string
SecretAccessKey : string
}
let targetTypeShape = shapeof<AwsConfig> //targetTypeShape is of type targetTypeShape<AwsConfig>
match targetTypeShape with
| Shape.FSharpRecord (:? ShapeFSharpRecord<AwsConfig> as shape) -> foo shape
// 'shape' is of type ShapeFSharpRecord<AwsConfig>, which is important //
| _ -> failwith "some other cases"
Но теперь я хотел бы создать динамически shapeof
, как
let awsConfigInstance = {AccessKeyId="123";DefaultRegion="asd";SecretAccessKey="asddd"}
let awsType = awsConfigInstance.GetType()
let targetTypeShape = shapeof<awsType> //that doesn't compile obviously
Поэтому я подумал, что мог бы сделать что-то вроде этого
let typeShape = TypeShape.Create (awsConfigInstance.GetType())
match typeShape with
//'shape' is of type IShapeFSharpRecord not ShapeFSharpRecord<AwsConfig> as i need it too be
| Shape.FSharpRecord shape->
let castedShape = shape :?> ShapeFSharpRecord<_> //error
foo castedShape
ошибка в строке shape :?> ShapeFSharpRecord<_>
выглядит следующим образом:
System.InvalidCastException: 'Unable to cast object of type
'ShapeFSharpRecord`1[FsConfig.Tests.Common AwsConfig]' to type
'ShapeFSharpRecord`1[Microsoft.FSharp.Core.FSharpOption`1[FsConfig.Tests.Common AwsConfig]]'.'
Я тоже попробовал этот трюк:
let typeShape = TypeShape.Create (awsConfigInstance.GetType())
match typeShape with
//'shape' is of type IShapeFSharpRecord not ShapeFSharpRecord<AwsConfig> as i need it too be
| Shape.FSharpRecord shape->
let temp = Activator.CreateInstanceGeneric<ShapeFSharpRecord<_>>([|typeShape .Type|], [||])
let castedShape = temp :?> ShapeFSharpRecord<_> //error
foo castedShape
Ошибка на линии let castedShape = temp :?> ShapeFSharpRecord<_>
'Unable to cast object of type 'ShapeFSharpRecord`1[FsConfig.Tests.Common AwsConfig]'
to type 'ShapeFSharpRecord`1[Microsoft.FSharp.Core.FSharpOption`1[FsConfig.Tests.Common AwsConfig]]'.'
Я понятия не имею, откуда это Microsoft.FSharp.Core.FSharpOption
берется.
Есть идеи, как я мог бы динамически создать экземпляр ShapeFSharpRecord?
Комментарии:
1. Есть только одно место, откуда может исходить опция: тип
foo
. Вы не показали код дляfoo
, но полученное сообщение об ошибке определенно указывает на то, чтоfoo
ожидается параметр типаShapeFSharpRecord<AwsConfig option>
2. Это правда! Я имею в виду, что на самом
foo
деле ожидаетShapeFSharpRecord<AwsConfig>
, но когда я удаляюfoo shape
строку, я получаю ошибку'Unable to cast object of type 'ShapeFSharpRecord`1[FsConfig.Tests.Common AwsConfig]' to type 'ShapeFSharpRecord`1[System.Object]'.'
3.
foo
определенно не ожидает того, чего, по вашим словам, он ожидает. Он определенно ожидает тип, включающийoption
. Если вы покажете кодfoo
, возможно, я смогу указать на это более точно. Если вы удалите вызов tofoo
, то при отсутствии каких-либо оснований для вывода целевого типа компилятор вернется кObject
.4. Точка зрения Бартека заключается в том, что
foo
это не имеет значения и может быть полностью удалено. Проблема в том, что динамическая версия кода (TypeShape.Create
) завершается неудачно, в то время как статическая версия (shapeof<AwsConfig>
) завершается успешно.5. Просто попробуй
shape :?> ShapeFSharpRecord<AwsConfig>
. Вы получите вызов ошибки во время компиляцииfoo
, но само приведение будет работать. Удалитеfoo
вызов для проверки.
Ответ №1:
Я ничего не знаю о типографии, но я просто немного просмотрел ее исходный код и воспроизвел то, что вы видите. К сожалению, я думаю, что короткий ответ просто «вы не можете этого сделать».
Чтобы быть более конкретным, если вы хотите получить доступ к базовой форме an FSharpRecord
, вам необходимо знать ее тип во время компиляции. Если вы попытаетесь усовершенствовать его , приведя к ShapeFSharpRecord<_>
, компилятор не сможет определить тип и вместо этого использует obj
(т. Е. System.Object
).
Итак, фактический тип фигуры таков ShapeFSharpRecord<AwsConfig>
, но вы пытаетесь привести ее к a ShapeFSharpRecord<obj>
, что невозможно сделать и приводит к исключению во время выполнения.
(Я игнорирую проблемы, связанные с подписью foo
функции, которые, по-моему, не являются центральными в вашем вопросе.)
Комментарии:
1. пока я просто откажусь от неудачи 🙂 пока я пытаюсь узнать больше о точке зрения @fyodor, но как только я закончу, я подумаю о том, чтобы уступить