Question

I have this relatively simple program:

open System
open System.ComponentModel.Composition
open System.ComponentModel.Composition.Hosting
open System.Reflection

module Config =
    [<Export("Timer.Delay")>]
    let Delay = TimeSpan.FromSeconds(5.0)

[<EntryPoint>]
let main argv = 
    let catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly())
    let container = new CompositionContainer(catalog)
    let delay = container.GetExportedValue<TimeSpan> "Timer.Delay"

    printfn "Delay: %A" delay

But I get this error on calling container.GetExportedValue<TimeSpan> "Timer.Delay":

More than one export was found that matches the constraint:

 ContractName     Timer.Delay

 RequiredTypeIdentity System.TimeSpan

Inspecting the catalog.Parts collection, I see two parts, each with a single ExportDefinition. The first one for Program+Config, which I would expect to find, and one for <StartupCode$Remote>.$Program (note the assembly name is Remote):

catalog.Parts

Wrapping the main function in a module Program does not change this behavior, nor does separating these modules into different files. Does anybody know why this F# program is generating a second export definition? And how can I prevent this?

Was it helpful?

Solution

After fiddling with it for a little bit, I think I've figured it out. My guess is that when the F# compiler sees an untargeted attribute on a property like the one above, it actually emits two attributes, one for the property and one for the field. It's probably also relevant that the ExportAttribute may be applied to properties and fields. Specifying a target on the attribute seems to resolve this issue.

This will generate the Program+Config part:

module Config =
    [<property: Export("Timer.Delay")>]
    let Delay = TimeSpan.FromSeconds(5.0)

This will generate the <StartupCode$Remote>.$Program part:

module Config =
    [<field: Export("Timer.Delay")>]
    let Delay = TimeSpan.FromSeconds(5.0)

Both of these will solve my problem, but the first one seems better, since it binds the Export attribute to a member of the actual module, rather than to some compiler-generated code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top