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

时间:2016-02-02 04:37:39

标签: f# type-providers

在我的first attempt中创建一个类型提供者,我有一条消息的ProvideTypeDefinition:

// 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 个答案:

答案 0 :(得分:2)

这可能不是问题,但很快就会看到line you linked可能实际上是问题:

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将其嵌入到其他属性/函数的调用代码中。这对于已擦除的类型尤其重要,因为无论如何反射都不会对它们起作用。