简体   繁体   中英

F# How to create an instance of a provided type

In my first attempt to create a type provider, I have a ProvidedTypeDefinition for a message:

// 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

Then I need to create an instance of that type in a method of another provided type. I am doing this:

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 shows the following C# code equivalent for the method:

public Car Car(IDirectBuffer buffer)
        {
            return new Car(buffer);
        }

and it also shows that the Car struct is present in the test assembly (this test assembly builds OK unless I access the Car method):

在此输入图像描述

But when I try to create the Car via the method like this:

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

I get the following errors:

  • The module/namespace 'SBETypeProvider' from compilation unit 'tmp5CDE' did not contain the namespace, module or type 'Car'

  • A reference to the type 'SBETypeProvider.Car' in assembly 'tmp5CDE' was found, but the type could not be found in that assembly

What I am doing wrong? The picture shows that the type is here. Why I cannot create it?

I looked through many type providers on GitHub and cannot find a clear example how to generate a ProvidedTypeDefinition from another one.

This might not be the problem, but at a quick glance it looks like the line you linked might actually be the issue:

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

This type is being added to the ty provided type (the one that will actually be written to the temporary assembly) and so shouldn't have the assembly and namespace specified itself.

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

Might work better. Generated types are a bit of a black art though, with very little documentation, so it's possible (probable?) that there will be other issues you might find.

On a more general note, for creating provided types what I normally end up doing is returning the provided constructor as a value which can then be embedded in the invoke code for other properties/functions using Expr.Call . This is especially important for erased types, as reflection will not work on them anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM