F# 向生成的类型添加接口

F# 向生成的类型添加接口,f#,type-providers,F#,Type Providers,在尝试编写类型提供程序时,我遇到了一个问题,特别是在添加具有提供类型的泛型参数的现有接口方面,我不能完全克服这个问题。如果有人知道如何将具有泛型参数的现有接口添加到生成的类型中 我想要的是生成一个类似于下面的类型,其中Bar和Foo都是生成的类型。显然,下面的例子是人为的 type Bar() = member val List: IEnumerable<Foo> with get, set type Bar()= 成员值列表:IEnumerable with get,se

在尝试编写类型提供程序时,我遇到了一个问题,特别是在添加具有提供类型的泛型参数的现有接口方面,我不能完全克服这个问题。如果有人知道如何将具有泛型参数的现有接口添加到生成的类型中

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

type Bar() =
    member val List: IEnumerable<Foo> with get, set
type Bar()=
成员值列表:IEnumerable with get,set
不幸的是,我在尝试使用实现接口
typeof
的ProvidedType时出错。我怀疑这是因为生成的类型被用作泛型参数

异常消息类似于:

不应在提供的上调用项“Foo”上的操作“Module” 类型、成员或参数

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

let buildType()=
让providedType1=ProvidedTypeDefinition(“父类型”,某些类型的,iSeries=false)
让providedType2=ProvidedTypeDefinition(“数据类型”,某些类型的,iSeries=false)
让symbolType=ProvidedTypeBuilder.MakeGenericType(typedefof,[providedType2])
设providedField=providedField(“propertyField”,symbolType)
providedType1.AddMember(providedField)
让providedProperty=providedProperty(“TestProperty”,symbolType)
ProviderProperty.GetterCode Expr.FieldGet(参数[0],ProviderField)
providedType1.AddMember providedProperty
设pconstructor=ProvidedConstructor([ProvidedParameter(“dataList”,symbolType)])
pconstructor.InvokeCode
提供的类型1.AddMember pconstructor
让nestedProperty=ProvidedProperty(“数据”,typeof)
nestedProperty.GetterCode
providedType2.AddMember nestedProperty
让interfaceType=ProvidedTypeBuilder.MakeGenericType(typedefof,[providedType2])
providedType2.AddInterfaceImplementation接口类型
让equalsParameter=ProvidedParameter(“其他”,providedType2)
让providedMethodEquals=ProvidedMethod(“Equals”,[equalsParameter],typeof)
providedMethodEquals.InvokeCode
设propertyGet x=Expr.propertyGet(x,nestedProperty)
设currentEq=propertyGet参数。[0]
让otherEq=propertyGet参数[1]
//将它们添加到生成的类型中,命名空间在此方法之外
[提供的类型1;提供的类型2]
堆栈跟踪看起来像:

在Microsoft.FSharp.Core.Operators.Raise[T](异常exn)的 ProviderImplementation.ProvidedTypes.Misc.notRequired[a](字符串 opname,字符串项)ProvidedTypes.fs:第58行\at ProviderImplementation.ProvidedTypes.ProvidedTypeDefinition.get_模块() 在ProvidedTypes.fs中:第1683行 位于的System.Reflection.Emit.AssemblyBuilder.CheckContext(类型[]类型) System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(类型 类型,布尔getGenericDefinition)位于 System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(类型, 布尔getGenericDefinition)位于 System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(类型 clsArgument,布尔值lastWasGenericInst)位于 System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(类型 clsArgument,布尔值lastWasGenericInst)位于 System.Reflection.Emit.SignatureHelper.GetType SigToken(模块修改, 类型)在 System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(类型 类型,布尔getGenericDefinition)位于 System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(类型, 布尔getGenericDefinition)位于 System.Reflection.Emit.TypeBuilder.AddInterfaceImplementation(类型 接口类型)


经过进一步调查,似乎类型提供程序启动包中生成的类型API目前还不支持此功能。我提出了一个关于这个案子的问题。我怀疑添加到TypeBuilder的接口类型需要从提供的TypeDefinition转换为实际反射。在作为接口添加到其他生成的类型(包括接口类型的所有泛型类型参数)之前,请发出TypeBuilder


i、 e对于IEnumerable——我们需要首先转换泛型类型参数GeneratedType,然后创建一个引用转换类型的新类型实例(IEnumerable),然后将其添加为接口实现。向类型添加接口的代码位于ProvidedTypes.fs文件的AssemblyGenerator中。

进一步调查后,类型提供程序启动包中生成的类型API似乎到目前为止还不支持此功能。我提出了一个关于这个案子的问题。我怀疑添加到TypeBuilder的接口类型需要从提供的TypeDefinition转换为实际反射。在作为接口添加到其他生成的类型(包括接口类型的所有泛型类型参数)之前,请发出TypeBuilder


i、 e对于IEnumerable——我们需要首先转换泛型类型参数GeneratedType,然后创建一个引用转换类型的新类型实例(IEnumerable),然后将其添加为接口实现。向类型添加接口的代码位于ProvidedTypes.fs文件的AssemblyGenerator中。

您可能会看到使用
ProvidedTypeBuilder.MakeGenericType
是否有帮助。这让我更进一步,但现在我对IEnumerable的ProvidedSymbolType有一个问题-它并不抱怨不应该调用GetAttributeFlagsImpl。我不确定是否应尝试在提供的SymbolType上实现该方法,或者是否执行了其他错误操作。创建一个实现GetAttributeFlagsImpl的自定义SymbolType从传入的泛型IEnumerable类型获取其类型属性以生成它(修改后的ProvidedTypeBuilder.MakeGenericType将捕获此信息)把我带回到办公室
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 ]