Как я могу обернуть тип F #, чтобы получить доступ к его свойствам

Я не знаю, действительно ли это шаблон, поэтому не знаю, с чего начать. Я постараюсь объяснить, что хочу.

Учитывая тип Foo с членами Bar и Baz, могу ли я создать тип оболочки A<Foo>, который возвращает фиктивный экземпляр Foo, чтобы я мог писать A<Foo>.Bar ...? Цель состоит в том, чтобы его можно было использовать внутри цитат, например <@ A<Foo>.Bar > 1 @>

Чтобы было ясно. Как реализовать A?


person alakfq    schedule 14.06.2018    source источник


Ответы (2)


Да, это шаблон.

Если вы каким-то образом анализируете свойства Foo, используйте цитату типа Expr<Foo -> 'a>, которая будет выглядеть так:

let q = <@ fun (foo: Foo) -> foo.Bar @>

Вы можете опустить аннотацию типа : Foo, если тип цитаты известен из контекста:

let q : Expr<Foo -> 'a> = <@ fun foo -> foo.Bar @>

Многие библиотеки используют цитаты таким образом, включая выражение query вычисления и одно из моих любимых, Argu, библиотеку для синтаксического анализа аргументов командной строки.

person Fyodor Soikin    schedule 14.06.2018
comment
А как мне реализовать A? - person alakfq; 14.06.2018
comment
Вы не реализуете A. Тип не может изменять свой набор членов в зависимости от своих универсальных аргументов. Я предполагал, что вы это уже поняли и просите альтернативный способ достижения своей цели. - person Fyodor Soikin; 14.06.2018

Возможно, с помощью Type Provider можно будет делать именно то, что вы хотите, но это, вероятно, потребует гораздо больше усилий, чем оно того стоит. В вашей ситуации я бы просто использовал фреймворк для фиксации вроде Foq, или, если варианты использования достаточно просты, просто используйте объектные выражения:

type Foo =
    abstract member Bar: int

let mockFoo = 
    {new Foo with
        member __.Bar = 1
    }

Вот пример чего-то близкого к тому, что вы ищете, используя Foq:

open Foq

type A<'a when 'a: not struct> = Mock<'a>

type Foo =
    abstract member Bar: int

<@ A<Foo>().Create().Bar > 1 @> 

В этом случае Bar всегда будет 0. Если вы хотите, чтобы оно было отличным от нуля, вам необходимо настроить его следующим образом:

<@ A<Foo>().Setup(fun f -> <@ f.Bar @>).Returns(2).Create().Bar > 1 @> 
person Aaron M. Eshbach    schedule 14.06.2018