Having a go at writing a type provider and I've come across a problem I can't quite get past specifically with regard to adding existing interfaces with generic parameters that are ProvidedTypes. If anyone knows how to add existing interfaces with generic parameters onto the generated types?
What I want is to generate a type similar to the following with both Bar and Foo being generated types. Obviously the below is a contrived example.
type Bar() =
member val List: IEnumerable<Foo> with get, set
Unfortunately I'm getting an error when trying to use a ProvidedType that implements the interface typeof<IEnumerable<Foo>>. I suspect it is because a generated type is being used as a generic parameter.
The exception message is something like:
The operation 'Module' on item 'Foo' should not be called on provided type, member or parameter
EDIT: I've added simple code to reproduce the error (called in 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 ]
Stack trace looks like:
at Microsoft.FSharp.Core.Operators.Raise[T](Exception exn) at ProviderImplementation.ProvidedTypes.Misc.notRequired[a](String opname, String item) ProvidedTypes.fs:line 58\ at ProviderImplementation.ProvidedTypes.ProvidedTypeDefinition.get_Module() in ProvidedTypes.fs:line 1683 at System.Reflection.Emit.AssemblyBuilder.CheckContext(Type[] types) at System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition) at System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition) at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst) at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst) at System.Reflection.Emit.SignatureHelper.GetType SigToken(Module mod, Type type) at System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition) at System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition) at System.Reflection.Emit.TypeBuilder.AddInterfaceImplementation(Type interfaceType)
ProvidedTypeBuilder.MakeGenericTypehelps. - kvb