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

5
在我创建类型提供程序的第一次尝试中,我有一个用于消息的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

我需要在另一个提供的类型的方法中创建该类型的实例。我正在执行以下操作:
let mMethod = ProvidedMethod(message.Key, [ProvidedParameter("buffer", typeof<IDirectBuffer>)], mTy)
          mMethod.InvokeCode <- (fun [this;buffer] ->
                let c = mTy.GetConstructors().Last()
                Expr.NewObject(c, [ buffer ])
          )

ILSpy显示以下C#代码,对应于该方法:
public Car Car(IDirectBuffer buffer)
        {
            return new Car(buffer);
        }

同时也显示出Car结构体存在于测试程序集中(只有当我访问Car方法时,这个测试程序集才能正常构建):

enter image description here

但是当我尝试通过以下方法创建汽车时:
type CarSchema = SbeProvider<"Path\to\SBETypeProvider\SBETypeProvider\Car.xml">
module Test =
  let carSchema = CarSchema()
  let car = carSchema.Car(null)

我遇到了以下错误:
  • 来自编译单元'tmp5CDE'的模块/命名空间'SBETypeProvider'不包含命名空间、模块或类型'Car'

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

我做错了什么?图片显示该类型已经存在。为什么我不能创建它?

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

1个回答

2

这可能不是问题所在,但仔细一看,你提供的链接中的代码可能就是问题所在:

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

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

let mTy = ProvidedTypeDefinition(message.Key, Some(typeof<ValueType>), 
                        HideObjectMethods = true, IsErased = false)

可能会更好用。生成的类型有点黑魔法,文档很少,所以可能(很可能)会出现其他问题。

总的来说,对于创建提供的类型,我通常会返回提供的构造函数作为一个值,然后可以在其他属性/函数的调用代码中使用Expr.Call嵌入。这对于擦除的类型尤其重要,因为反射不管用。


谢谢!是的,这个错误重载问题是我提问的几个问题之一,也可能是主要问题!我已经向GitHub StarterPack提交了另一个关于结构体的问题。从您的名字和图片来看,我猜测您是主要贡献者。 - V.B.
我现在通过浏览大多数已知的TP和F#专家的帮助,建立了更好的TPs心理模型。过载是主要问题,但仍有许多“微妙之处”,如程序集解析。为什么它仍然像你所说的“黑魔法”一样?TPs是F#最受赞誉、最酷、最独特和最强大的功能之一,但当涉及到新实现时,人们确实会迷失方向。他们在开始时就像盲小猫一样完全迷失了方向 :) 如何改进文档? - V.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接