1

I'd like to be able to parametrize my exports not only with types (as in, generic exports), but also with values.

Something like:

    class Greeter
    {
        readonly string _format;
        public Greeter( string format ) { _format = format; }

        public string Greet( string name ) { return string.Format( _format, name ); }
    }

    // ...

    var e = new ExportProvider();
    e.ExportParametrized<Greeter>( args: new[] { "Hi, {0}!" } );
    e.ExportParametrized<Greeter>( args: new[] { "¡Hola, {0}!" } );

    // And then:
    [ImportMany] IEnumerable<Greeter> Greeters { get; set; }

    foreach( var g in Greeters ) Console.WriteLine( g.Greet( "John" ) );

    // Should print out:
    //   Hello, John!
    //   ¡Hola, John!

One might ask: why don't I simply export the value new Greeter( "Hello, {0}!" ) using ComposablePartExportProvider and CompositionBatch?
While this approach would work in this particular case, it has an important flaw: if the Greeter class had any imports of its own, they would not be satisfied.

The usual way I would go about this is to declare two classes - EnglishGreeter and SpanishGreeter, inherit them both from Greeter, and then provide the appropriate arguments in the call to base constructor.

But this doesn't work for two reasons:

  1. This is a lot of noise to write. Not only do I have to type the whole shebang, I also have to come up with names for those classes, and it doesn't always make sense to have names. Not to mention the DRY principle. But even besides the noise...
  2. Sometimes I don't know the parameters upfront. Say, for example, my greeting formats were coming from some kind of config file.

Here is another thought, to somewhat clarify what I'm looking for.
This problem is almost solved in the TypeCatalog. See, the TypeCatalog knows about the type and it calls the type's constructor to create the part on demand.
One can think of this process from another standpoint: the catalog has a factory function; using that function, it creates the part, then satisfies its non-prerequisite imports, and then returns the part back to the requestor.
Now, in the particular case of TypeCatalog, the factory function just happens to be the type's own constructor. If only I could hook in and replace the factory function with my own, but still leverage the rest of the machinery, that would be exactly what I'm looking for.

4

1 回答 1

2

您可以通过使用属性导出来实现此目的。您可以专门为这些类型的导出定义一个类,它看起来像这样:

class MyParameterizedExports
{
    [Export(typeof(Greeter))]
    private Greeter EnglishGreeter
    {
        get
        {
            Greeter g = new Greeter("Hi, {0}!");
            container.SatisfyImportsOnce(g);
            return g;
        }
    }

    [Export(typeof(Greeter))]
    private Greeter SpanishGreeter
    {
        get
        {
            Greeter g = new Greeter("¡Hola, {0}!");
            container.SatisfyImportsOnce(g);
            return g;
        }
    }
}

在这里,您可以导出两个单独Greeter的实例,而无需为每种类型定义一个新类Greeter

于 2012-11-26T15:12:48.763 回答