将接口添加到生成的类型

时间:2016-05-05 12:49:43

标签: f# type-providers

编写一个类型提供程序并且我遇到了一个问题,我无法完全解决使用ProvideTypes的泛型参数添加现有接口的问题。如果有人知道如何将现有接口与通用参数一起添加到生成的类型中?

我想要的是生成类似于以下类型的类型,Bar和Foo都是生成类型。显然,以下是一个人为的例子。

type Bar() =
    member val List: IEnumerable<Foo> with get, set

不幸的是,我在尝试使用实现接口typeof<IEnumerable<Foo>>的ProvideType时遇到错误。我怀疑这是因为生成的类型被用作通用参数。

异常消息类似于:

  

不应在提供的情况下调用项目'Foo'上的操作'Module'   类型,成员或参数

编辑:我添加了简单的代码来重现错误(在DefineStaticParameters中调用):

let buildType() = 
    let providedType1 = ProvidedTypeDefinition("ParentType", Some typeof<obj>, IsErased = false)
    let providedType2 = ProvidedTypeDefinition("DataType", Some typeof<obj>, IsErased = false)

    let symbolType = ProvidedTypeBuilder.MakeGenericType(typedefof<IEnumerable<_>>, [providedType2])

    let providedField = ProvidedField("propertyField", symbolType)
    providedType1.AddMember(providedField)

    let providedProperty = ProvidedProperty("TestProperty", symbolType)
    providedProperty.GetterCode <- fun args -> Expr.FieldGet(args.[0], providedField)
    providedType1.AddMember providedProperty

    let pconstructor = ProvidedConstructor([ProvidedParameter("dataList", symbolType)])
    pconstructor.InvokeCode <- fun args -> <@@ () @@>
    providedType1.AddMember pconstructor

    let nestedProperty = ProvidedProperty("Data", typeof<string>)
    nestedProperty.GetterCode <- fun _ -> <@@ "TEST SUCCESS" @@>
    providedType2.AddMember nestedProperty

    let interfaceType = ProvidedTypeBuilder.MakeGenericType(typedefof<IEquatable<_>>, [providedType2])
    providedType2.AddInterfaceImplementation interfaceType

    let equalsParameter = ProvidedParameter("other", providedType2)
    let providedMethodEquals = ProvidedMethod("Equals", [ equalsParameter ], typeof<bool>)
    providedMethodEquals.InvokeCode <- fun args ->
        let propertyGet x = Expr.PropertyGet(x, nestedProperty)
        let currentEq = propertyGet args.[0]
        let otherEq = propertyGet args.[1]
        <@@ %%currentEq = %%otherEq @@>

    // Add these to the generated type with a namespace outside this method
    [ providedType1; providedType2 ]

堆栈跟踪看起来像:

  

at Microsoft.FSharp.Core.Operators.Raise [T](Exception exn)at at   ProviderImplementation.ProvidedTypes.Misc.notRequired并[a](字符串   opname,String item)ProvideTypes.fs:第58行\ at   ProviderImplementation.ProvidedTypes.ProvidedTypeDefinition.get_Module()   在ProvideTypes.fs中:第1683行   System.Reflection.Emit.AssemblyBuilder.CheckContext(Type [] types)at   System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(类型   type,Boolean getGenericDefinition)at   System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type,   布尔getGenericDefinition)at   System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(类型   clsArgument,Boolean lastWasGenericInst)at   System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(类型   clsArgument,Boolean lastWasGenericInst)at   System.Reflection.Emit.SignatureHelper.GetType SigToken(Module mod,   输入类型)   System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(类型   type,Boolean getGenericDefinition)at   System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type,   布尔getGenericDefinition)at   System.Reflection.Emit.TypeBuilder.AddInterfaceImplementation(类型   interfaceType)

1 个答案:

答案 0 :(得分:0)

经过进一步调查后,似乎类型提供程序初学者包中的Generated Types API不支持此功能。我提出了一个问题来解决这个问题。我怀疑添加到TypeBuilder的接口类型需要从ProvideTypeDefinition转换为实际的Reflection.Emit TypeBuilders,然后再作为接口添加到其他生成的类型,包括接口类型的所有泛型类型参数。

即IEnumerable&lt; GeneratedType&gt; - 我们需要首先转换泛型类型参数GeneratedType,然后创建一个引用转换类型的新类型实例(IEnumerable&lt; GeneratedType&gt;),然后将其添加为接口实现。将接口添加到类型的代码位于ProvideTypes.fs文件的AssemblyGenerator中。