F# 如何创建所提供类型的实例

V.B*_*.B. 5 f# type-providers

在我第一次尝试创建类型提供程序时,我有一个消息的 ProvidedTypeDefinition:

// Message type
          let mTy = ProvidedTypeDefinition(asm, ns, message.Key, Some(typeof<ValueType>), 
                        HideObjectMethods = true, IsErased = false)
          // Direct buffer
          let bufferField = ProvidedField("_directBuffer", typeof<IDirectBuffer>)
          mTy.AddMember bufferField

          let mCtor1 = 
            ProvidedConstructor(
              [ProvidedParameter("buffer", typeof<IDirectBuffer>)], 
              InvokeCode = fun args ->
                match args with
                | [this;buffer] ->
                  Expr.FieldSet (this, bufferField, <@@ %%buffer:IDirectBuffer @@>)
                | _ -> failwith "wrong ctor params"
            )
          mTy.AddMember mCtor1
Run Code Online (Sandbox Code Playgroud)

然后我需要在另一个提供的类型的方法中创建该类型的实例。我正在这样做:

let mMethod = ProvidedMethod(message.Key, [ProvidedParameter("buffer", typeof<IDirectBuffer>)], mTy)
          mMethod.InvokeCode <- (fun [this;buffer] ->
                let c = mTy.GetConstructors().Last()
                Expr.NewObject(c, [ buffer ])
          )
Run Code Online (Sandbox Code Playgroud)

ILSpy 显示了该方法的以下等效 C# 代码:

public Car Car(IDirectBuffer buffer)
        {
            return new Car(buffer);
        }
Run Code Online (Sandbox Code Playgroud)

它还显示该Car结构存在于测试程序集中(除非我访问该Car方法,否则该测试程序集构建正常):

在此输入图像描述

但是当我尝试通过这样的方法创建汽车时:

type CarSchema = SbeProvider<"Path\to\SBETypeProvider\SBETypeProvider\Car.xml">
module Test =
  let carSchema = CarSchema()
  let car = carSchema.Car(null)
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

  • 编译单元“tmp5CDE”中的模块/命名空间“SBETypeProvider”不包含命名空间、模块或类型“Car”

  • 找到了程序集“tmp5CDE”中对类型“SBETypeProvider.Car”的引用,但在该程序集中找不到该类型

我做错了什么?如图所示,类型就在这里。为什么我无法创建它?

我浏览了 GitHub 上的许多类型提供程序,但找不到如何ProvidedTypeDefinition从另一个类型提供程序生成 a 的清晰示例。

mav*_*vnn 2

这可能不是问题,但乍一看,您链接的行实际上可能是问题所在:

let mTy = ProvidedTypeDefinition(asm, ns, message.Key, Some(typeof<ValueType>), 
                        HideObjectMethods = true, IsErased = false)
Run Code Online (Sandbox Code Playgroud)

该类型将被添加到ty提供的类型(实际上将写入临时程序集的类型),因此不应自行指定程序集和命名空间。

let mTy = ProvidedTypeDefinition(message.Key, Some(typeof<ValueType>), 
                        HideObjectMethods = true, IsErased = false)
Run Code Online (Sandbox Code Playgroud)

可能会工作得更好。不过,生成的类型有点像魔术,文档很少,因此您可能会发现其他问题(可能?)。

更一般地说,为了创建提供的类型,我通常最终要做的是将提供的构造函数作为值返回,然后可以使用Expr.Call. 这对于擦除类型尤其重要,因为反射无论如何都不会作用于它们。