FSharp.TypeProviders.SDK
FSharp.TypeProviders.SDK copied to clipboard
Can not add generic interface onto ProvidedTypeDefinition
Adding an interface to a generated type doesn't work; particuarly in the case where it is an existing interface that has generic arguments that are provided types. This is a common use case for us since I want to generate types that have implementation of IComparable<GeneratedType>, IEquatable<GeneratedType>, etc. Looking at the ProvidedTypes.fs code I'm not quite sure about the best way to fix this without breaking something else. If anyone can give me some guidance about either fixing it or working around it as well would appreciate it.
To reproduce:
Create a generative type provide that creates a parent type to add all your types to then use the following method to get a list of types to add to it:
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 -> <@@ Expr.FieldSet(args.[0], providedField, args.[1]) @@>
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 ]`
Then it is as simple as trying to use the Generative Type Provider you have created.
What I expect is that the generated type is useable and has both the members for the interface added and properly extends the interface with another generated type as its generic argument. What I get unfortunately is exceptions similar to the following: "The operation 'Module' on item 'IEquatable<DataType>' should not be called on provided type, member or parameter"
Unfortunately I don't see workarounds for the issue.
Tested under Mono 4.2.3 and Windows 7 with Visual Studio 2015.
@mvkra Did you ever resolve this?
No never resolved this - ended up using a different clunkier approach if I recall (other than TP's) which is a shame. Better late reply than never.
What's the recommended approach to generating comparison and equality on provided types?