Panoramica sul modello di programmazione con attributi (MEF)Attributed Programming Model Overview (MEF)

In Managed Extensibility Framework (MEF) un modello di programmazione è un metodo particolare per definire l'insieme di oggetti concettuali su cui opera MEF,In the Managed Extensibility Framework (MEF), a programming model is a particular method of defining the set of conceptual objects on which MEF operates. incluse le parti, le importazioni e le esportazioni.These conceptual objects include parts, imports, and exports. MEF usa questi oggetti, ma non specifica il modo in cui devono essere rappresentati.MEF uses these objects, but does not specify how they should be represented. È quindi possibile usare una vasta gamma di modelli di programmazione, inclusi i modelli di programmazione personalizzati.Therefore, a wide variety of programming models are possible, including customized programming models.

Il modello di programmazione predefinito usato in MEF è il modello di programmazione con attributi.The default programming model used in MEF is the attributed programming model. Nel modello di programmazione con attributi le parti, le importazioni, le esportazioni e gli altri oggetti sono definiti con attributi che decorano le classi normali di .NET Framework.In the attributed programming model parts, imports, exports, and other objects are defined with attributes that decorate ordinary .NET Framework classes. Questo argomento illustra come usare gli attributi forniti dal modello di programmazione con attributi per creare un'applicazione MEF.This topic explains how to use the attributes provided by the attributed programming model to create a MEF application.

Nozioni fondamentali su importazione ed esportazioneImport and Export Basics

Un' esportazione è un valore fornito da una parte ad altre parti di un contenitore e un' importazione è un requisito espresso da una parte al contenitore, da soddisfare con le esportazioni disponibili.An export is a value that a part provides to other parts in the container, and an import is a requirement that a part expresses to the container, to be filled from the available exports. Nel modello di programmazione con attributi le importazioni e le esportazioni sono dichiarate tramite la decorazione di classi o membri con gli attributi Import e Export .In the attributed programming model, imports and exports are declared by decorating classes or members with the Import and Export attributes. L'attributo Export può decorare una classe, un campo, una proprietà o un metodo, mentre l'attributo Import può decorare un campo, una proprietà o un parametro di costruttore.The Export attribute can decorate a class, field, property, or method, while the Import attribute can decorate a field, property, or constructor parameter.

Per associare un'importazione a un'esportazione, è necessario che l'importazione e l'esportazione abbiano lo stesso contratto.In order for an import to be matched with an export, the import and export must have the same contract. Il contratto è costituito da una stringa, definita nome contratto, e dal tipo dell'oggetto esportato o importato, definito tipo di contratto.The contract consists of a string, called the contract name, and the type of the exported or imported object, called the contract type. Un'esportazione è in grado di soddisfare un'importazione specifica solo se il nome e il tipo di contratto corrispondono.Only if both the contract name and contract type match is an export considered to fulfill a particular import.

Uno o entrambi i parametri del contratto possono essere impliciti o espliciti.Either or both of the contract parameters can be implicit or explicit. Il codice seguente mostra una classe che dichiara un'importazione di base.The following code shows a class that declares a basic import.

Public Class MyClass1  
    <Import()>  
    Public Property MyAddin As IMyAddin  
End Class  
public class MyClass  
{  
    [Import]  
    public IMyAddin MyAddin { get; set; }  
}  

In questa importazione all'attributo Import non è associato alcun parametro nome contratto o tipo di contratto.In this import, the Import attribute has neither a contract type nor a contract name parameter attached. Entrambi i parametri saranno quindi dedotti dalla proprietà decorata.Therefore, both will be inferred from the decorated property. In questo caso il tipo di contratto sarà IMyAddine il nome del contratto sarà una stringa univoca creata dal tipo di contratto.In this case, the contract type will be IMyAddin, and the contract name will be a unique string created from the contract type. In altri termini, il nome del contratto corrisponderà solo alle esportazioni i cui nomi sono stati dedotti dal tipo IMyAddin.(In other words, the contract name will match only exports whose names are also inferred from the type IMyAddin.)

Di seguito è illustrata un'esportazione corrispondente all'importazione precedente.The following shows an export that matches the previous import.

<Export(GetType(IMyAddin))>  
Public Class MyLogger  
    Implements IMyAddin  

End Class  
[Export(typeof(IMyAddin))]  
public class MyLogger : IMyAddin { }  

In questa esportazione il tipo di contratto è IMyAddin poiché è specificato come parametro dell'attributo Export .In this export, the contract type is IMyAddin because it is specified as a parameter of the Export attribute. Il tipo esportato deve essere uguale al tipo di contratto, deve derivare dal tipo di contratto o deve implementare il tipo di contratto come se fosse un'interfaccia.The exported type must be either the same as the contract type, derive from the contract type, or implement the contract type if it is an interface. In questa esportazione il tipo effettivo MyLogger implementa l'interfaccia IMyAddin.In this export, the actual type MyLogger implements the interface IMyAddin. Il nome del contratto è dedotto dal tipo di contratto. Questa esportazione corrisponderà quindi all'importazione precedente.The contract name is inferred from the contract type, which means that this export will match the previous import.

Nota

Le esportazioni e le importazioni devono essere in genere dichiarate nelle classi o nei membri pubblici.Exports and imports should usually be declared on public classes or members. Sono supportate altre dichiarazioni, ma l'esportazione o l'importazione di un membro privato, protetto o interno influisce negativamente sul modello di isolamento per la parte e non è quindi consigliata.Other declarations are supported, but exporting or importing a private, protected, or internal member breaks the isolation model for the part and is therefore not recommended.

Per fare in modo che l'esportazione e l'importazione siano considerate corrispondenti, il tipo di contratto deve corrispondere esattamente.The contract type must match exactly for the export and import to be considered a match. Esaminare l'esportazione seguente.Consider the following export.

<Export()> 'WILL NOT match the previous import!  
Public Class MyLogger  
    Implements IMyAddin  

End Class  
[Export] //WILL NOT match the previous import!  
public class MyLogger : IMyAddin { }  

In questa esportazione il tipo di contratto è MyLogger invece di IMyAddin.In this export, the contract type is MyLogger instead of IMyAddin. Anche se MyLogger implementa IMyAddined è quindi possibile eseguirne il casting in un oggetto IMyAddin , questa esportazione non corrisponderà all'importazione precedente perché i tipi di contratto non sono uguali.Even though MyLogger implements IMyAddin, and therefore could be cast to an IMyAddin object, this export will not match the previous import because the contract types are not the same.

In genere, non è necessario specificare il nome del contratto e la maggior parte dei contratti dovrebbe essere definita in termini di tipo di contratto e metadati.In general, it is not necessary to specify the contract name, and most contracts should be defined in terms of the contract type and metadata. In alcune circostanze, tuttavia, è importante specificare direttamente il nome del contratto.However, under certain circumstances, it is important to specify the contract name directly. Il caso più comune consiste nell'esportazione di alcuni valori che condividono un tipo comune, ad esempio le primitive, da parte di una classe.The most common case is when a class exports several values that share a common type, such as primitives. Il nome del contratto può essere specificato come primo parametro dell'attributo Import o Export .The contract name can be specified as the first parameter of the Import or Export attribute. Il codice seguente mostra un'importazione e un'esportazione con un nome contratto specificato MajorRevision.The following code shows an import and an export with a specified contract name of MajorRevision.

Public Class MyExportClass  

    'This one will match  
    <Export("MajorRevision")>  
    Public ReadOnly Property MajorRevision As Integer  
        Get  
            Return 4  
        End Get  
    End Property  

    <Export("MinorRevision")>  
    Public ReadOnly Property MinorRevision As Integer  
        Get  
            Return 16  
        End Get  
    End Property  
End Class  
public class MyClass  
{  
    [Import("MajorRevision")]  
    public int MajorRevision { get; set; }  
}  

public class MyExportClass  
{   
    [Export("MajorRevision")] //This one will match.  
    public int MajorRevision = 4;  

    [Export("MinorRevision")]  
    public int MinorRevision = 16;  
}  

Se il tipo di contratto non è specificato, sarà comunque dedotto dal tipo di importazione o esportazione.If the contract type is not specified, it will still be inferred from the type of the import or export. Anche se il nome del contratto è specificato in modo esplicito, tuttavia, anche il tipo di contratto deve corrispondere esattamente per fare in modo che l'importazione e l'esportazione siano considerate corrispondenti.However, even if the contract name is specified explicitly, the contract type must also match exactly for the import and export to be considered a match. Ad esempio, se il campo MajorRevision fosse una stringa, i tipi di contratto dedotti non corrisponderebbero e l'esportazione non corrisponderebbe all'importazione, nonostante entrambe abbiano lo stesso nome di contratto.For example, if the MajorRevision field was a string, the inferred contract types would not match and the export would not match the import, despite having the same contract name.

Importazione ed esportazione di un metodoImporting and Exporting a Method

L'attributo Export può anche decorare un metodo, in modo analogo a una classe, una proprietà o una funzione.The Export attribute can also decorate a method, in the same way as a class, property, or function. Le esportazioni di metodi devono specificare un tipo o un nome di contratto, poiché il tipo non può essere dedotto.Method exports must specify a contract type or contract name, as the type cannot be inferred. Il tipo specificato può essere un delegato personalizzato o un tipo generico, ad esempio Func.The specified type can be either a custom delegate or a generic type, such as Func. La classe seguente esporta un metodo denominato DoSomething.The following class exports a method named DoSomething.

Public Class MyAddin  

    'Explicitly specifying a generic type  
    <Export(GetType(Func(Of Integer, String)))>  
    Public Function DoSomething(ByVal TheParam As Integer) As String  
        Return Nothing 'Function body goes here  
    End Function  

End Class  
public class MyAddin  
{  
    //Explicitly specifying a generic type.  
    [Export(typeof(Func<int, string>)]  
    public string DoSomething(int TheParam);  
}  

In questa classe il metodo DoSomething accetta un singolo parametro int e restituisce un oggetto string.In this class, the DoSomething method takes a single int parameter and returns a string. Per corrispondere a questa esportazione, la parte che esegue l'importazione deve dichiarare un membro appropriato.To match this export, the importing part must declare an appropriate member. La classe seguente importa il metodo DoSomething.The following class imports the DoSomething method.

Public Class MyClass1  

    'Contract name must match!  
    <Import()>  
    Public Property MajorRevision As Func(Of Integer, String)  
End Class  
public class MyClass  
{  
    [Import] //Contract name must match!  
    public Func<int, string> DoSomething { get; set; }  
}  

Per altre informazioni su come usare l'oggetto Func<T, T> , vedere Func<T,TResult>.For more information about how to use of the Func<T, T> object, see Func<T,TResult>.

Tipi di importazioniTypes of Imports

MEF supporta diversi tipi di importazione, tra cui l'importazione dinamica, differita, essenziale o facoltativa.MEF support several import types, including dynamic, lazy, prerequisite, and optional.

Importazioni dinamicheDynamic Imports

In alcuni casi è possibile che la classe che esegue l'importazione voglia corrispondere a esportazioni di qualsiasi tipo con un nome di contratto specifico.In some cases, the importing class may want to match exports of any type that have a particular contract name. In questo scenario la classe può dichiarare una importazione dinamica.In this scenario, the class can declare a dynamic import. L'importazione seguente corrisponde a qualsiasi esportazione con nome contratto "TheString".The following import matches any export with contract name "TheString".

Public Class MyClass1  

    <Import("TheString")>  
    Public Property MyAddin  

End Class  
public class MyClass  
{  
    [Import("TheString")]  
    public dynamic MyAddin { get; set; }  
}  

Quando il tipo di contratto è dedotto dalla parola chiave dynamic , corrisponderà a qualsiasi tipo di contratto.When the contract type is inferred from the dynamic keyword, it will match any contract type. In questo caso un'importazione deve sempre specificare un nome di contratto a cui corrispondere.In this case, an import should always specify a contract name to match on. Se non è stato specificato alcun nome di contratto, l'importazione sarà considerata come non corrispondente ad alcuna esportazione. Entrambe le esportazioni seguenti corrispondono all'importazione precedente.(If no contract name is specified, the import will be considered to match no exports.) Both of the following exports would match the previous import.

<Export("TheString", GetType(IMyAddin))>  
Public Class MyLogger  
    Implements IMyAddin  

End Class  

<Export("TheString")>  
Public Class MyToolbar  

End Class  
[Export("TheString", typeof(IMyAddin))]  
public class MyLogger : IMyAddin { }  

[Export("TheString")]  
public class MyToolbar { }  

La classe che esegue l'importazione deve essere ovviamente preparata per la gestione di un oggetto di tipo arbitrario.Obviously, the importing class must be prepared to deal with an object of arbitrary type.

Importazioni differiteLazy Imports

In alcuni casi è possibile che la classe che esegue l'importazione necessiti di un riferimento indiretto all'oggetto importato, in modo che non siano create immediatamente istanze dell'oggetto.In some cases, the importing class may require an indirect reference to the imported object, so that the object is not instantiated immediately. In questo scenario la classe può dichiarare un' importazione differita usando un tipo di contratto Lazy<T>.In this scenario, the class can declare a lazy import by using a contract type of Lazy<T>. La proprietà di importazione seguente dichiara un'importazione differita.The following importing property declares a lazy import.

Public Class MyClass1  

    <Import()>  
    Public Property MyAddin As Lazy(Of IMyAddin)  

End Class  
public class MyClass  
{  
    [Import]  
    public Lazy<IMyAddin> MyAddin { get; set; }  
}  

Dal punto di vista del motore della composizione, un tipo di contratto Lazy<T> è considerato identico al tipo di contratto T.From the point of view of the composition engine, a contract type of Lazy<T> is considered identical to contract type of T. L'importazione precedente, quindi, corrisponderebbe all'esportazione seguente.Therefore, the previous import would match the following export.

<Export(GetType(IMyAddin))>  
Public Class MyLogger  
    Implements IMyAddin  

End Class  
[Export(typeof(IMyAddin))]  
public class MyLogger : IMyAddin { }  

Il nome e il tipo di contratto possono essere specificati nell'attributo Import per un'importazione differita, come illustrato in precedenza nella sezione "Nozioni fondamentali su importazione ed esportazione".The contract name and contract type can be specified in the Import attribute for a lazy import, as described earlier in the "Basic Imports and Exports" section.

Importazioni essenzialiPrerequisite Imports

Le parti MEF esportate sono in genere create dal motore della composizione, in risposta a una richiesta diretta o alla necessità di soddisfare un'importazione corrispondente.Exported MEF parts are typically created by the composition engine, in response to a direct request or the need to fill a matched import. Per impostazione predefinita, quando si crea una parte, il motore della composizione usa il costruttore senza parametri.By default, when creating a part, the composition engine uses the parameter-less constructor. Per fare in modo che il motore usi un costruttore diverso, è possibile contrassegnarlo con l'attributo ImportingConstructor .To make the engine use a different constructor, you can mark it with the ImportingConstructor attribute.

Ogni parte può avere solo un costruttore per l'uso da parte del motore della composizione.Each part may have only one constructor for use by the composition engine. Se non si specifica alcun costruttore predefinito e alcun attributo ImportingConstructor o se si specifica più di un attributo ImportingConstructor , si verificherà un errore.Providing no default constructor and no ImportingConstructor attribute, or providing more than one ImportingConstructor attribute, will produce an error.

Per compilare i parametri di un costruttore contrassegnato con l'attributo ImportingConstructor , tutti questi parametri sono dichiarati automaticamente come importazioni.To fill the parameters of a constructor marked with the ImportingConstructor attribute, all of those parameters are automatically declared as imports. Si tratta di una soluzione utile per dichiarare importazioni usate durante l'inizializzazione delle parti.This is a convenient way to declare imports that are used during part initialization. La classe seguente usa ImportingConstructor per dichiarare un'importazione.The following class uses ImportingConstructor to declare an import.

Public Class MyClass1  

    Private _theAddin As IMyAddin  

    'Default constructor will NOT be used  
    'because the ImportingConstructor  
    'attribute is present.  
    Public Sub New()  

    End Sub  

    'This constructor will be used.  
    'An import with contract type IMyAddin  
    'is declared automatically.  
    <ImportingConstructor()>  
    Public Sub New(ByVal MyAddin As IMyAddin)  
        _theAddin = MyAddin  
    End Sub  

End Class  
public class MyClass   
{  
    private IMyAddin _theAddin;  

    //Default constructor will NOT be  
    //used because the ImportingConstructor  
    //attribute is present.  
    public MyClass() { }  

    //This constructor will be used.  
    //An import with contract type IMyAddin is   
    //declared automatically.  
    [ImportingConstructor]   
    public MyClass(IMyAddin MyAddin)   
    {  
        _theAddin = MyAddin;  
    }  
}  

Per impostazione predefinita, l'attributo ImportingConstructor usa i tipi e nomi di contratto dedotti per tutte le importazioni di parametri.By default, the ImportingConstructor attribute uses inferred contract types and contract names for all of the parameter imports. È possibile eseguire l'override di questa procedura dichiarando i parametri con gli attributi Import , che possono quindi definire in modo esplicito il tipo e il nome del contratto.It is possible to override this by decorating the parameters with Import attributes, which can then define the contract type and contract name explicitly. Il codice seguente illustra un costruttore che usa questa sintassi per importare una classe derivata invece di una classe padre.The following code demonstrates a constructor that uses this syntax to import a derived class instead of a parent class.

<ImportingConstructor()>  
Public Sub New(<Import(GetType(IMySubAddin))> ByVal MyAddin As IMyAddin)  

End Sub  
[ImportingConstructor]   
public MyClass([Import(typeof(IMySubAddin))]IMyAddin MyAddin)   
{  
    _theAddin = MyAddin;  
}  

In particolare, occorre prestare attenzione ai parametri di raccolta.In particular, you should be careful with collection parameters. Se, ad esempio, si specifica ImportingConstructor su un costruttore con parametro di tipo IEnumerable<int>, l'importazione corrisponderà a una esportazione di tipo IEnumerable<int>, invece che a un insieme di esportazioni di tipo int.For example, if you specify ImportingConstructor on a constructor with a parameter of type IEnumerable<int>, the import will match a single export of type IEnumerable<int>, instead of a set of exports of type int. Per ottenere la corrispondenza a un insieme di esportazioni di tipo int, è necessario decorare il parametro con l'attributo ImportMany .To match a set of exports of type int, you have to decorate the parameter with the ImportMany attribute.

I parametri dichiarati come importazioni dall'attributo ImportingConstructor sono contrassegnati anche come importazioni essenziali.Parameters declared as imports by the ImportingConstructor attribute are also marked as prerequisite imports. MEF permette in genere a esportazioni e importazioni di formare un ciclo.MEF normally allows exports and imports to form a cycle. Ad esempio, un ciclo è rappresentato dall'oggetto A che importa l'oggetto B, che a sua volta importa l'oggetto A. In circostanze normali un ciclo non rappresenta un problema e il contenitore di composizione costruisce normalmente entrambi gli oggetti.For example, a cycle is where object A imports object B, which in turn imports object A. Under ordinary circumstances, a cycle is not a problem, and the composition container constructs both objects normally.

Se il costruttore di una parte necessita di un valore importato, tale oggetto non può essere incluso in un ciclo.When an imported value is required by the constructor of a part, that object cannot participate in a cycle. Se per la costruzione dell'oggetto A è necessaria prima di tutto la costruzione dell'oggetto B e l'oggetto B importa l'oggetto A, il ciclo non potrà essere risolto e si verificherà un errore di composizione.If object A requires that object B be constructed before it can be constructed itself, and object B imports object A, then the cycle will be unable to resolve and a composition error will occur. Le importazioni dichiarate nei parametri del costruttore sono quindi importazioni essenziali, che devono essere completate prima che sia possibile usare qualsiasi esportazione dall'oggetto che le richiede.Imports declared on constructor parameters are therefore prerequisite imports, which must all be filled before any of the exports from the object that requires them can be used.

Importazioni facoltativeOptional Imports

L'attributo Import specifica un requisito necessario per il funzionamento della parte.The Import attribute specifies a requirement for the part to function. Se non è possibile soddisfare un'importazione, la composizione della parte avrà esito negativo e la parte non sarà disponibile.If an import cannot be fulfilled, the composition of that part will fail and the part will not be available.

È possibile specificare che un'importazione è facoltativa usando la proprietà AllowDefault .You can specify that an import is optional by using the AllowDefault property. In questo caso, la composizione avrà esito positivo, anche se l'importazione non corrisponde ad alcuna esportazione disponibile, e la proprietà che esegue l'importazione sarà impostata sul valore predefinito per il tipo di proprietà specifico (null per proprietà degli oggetti, false per proprietà booleane oppure zero per proprietà numeriche). La classe seguente usa un'importazione facoltativa.In this case, the composition will succeed even if the import does not match any available exports, and the importing property will be set to the default for its property type (null for object properties, false for Booleans, or zero for numeric properties.) The following class uses an optional import.

Public Class MyClass1  

    <Import(AllowDefault:=True)>  
    Public Property thePlugin As Plugin  

    'If no matching export is available,  
    'thePlugin will be set to null.  
End Class  
public class MyClass  
{  
    [Import(AllowDefault = true)]  
    public Plugin thePlugin { get; set; }  

    //If no matching export is avaliable,  
    //thePlugin will be set to null.  
}  

Importazione di più oggettiImporting Multiple Objects

La composizione dell'attributo Import avrà esito positivo solo se corrisponde a una sola esportazione.The Import attribute will only be successfully composed when it matches one and only one export. Gli altri casi provocheranno un errore di composizione.Other cases will produce a composition error. Per importare più di un'esportazione che corrisponde allo stesso contratto, usare l'attributo ImportMany .To import more than one export that matches the same contract, use the ImportMany attribute. Le importazioni contrassegnate con questo attributo sono sempre facoltative.Imports marked with this attribute are always optional. Ad esempio, la composizione avrà esito positivo se non sono presenti esportazioni corrispondenti.For example, composition will not fail if no matching exports are present. La classe seguente importa qualsiasi numero di esportazioni di tipo IMyAddin.The following class imports any number of exports of type IMyAddin.

Public Class MyClass1  

    <ImportMany()>  
    Public Property MyAddin As IEnumerable(Of IMyAddin)  

End Class  
public class MyClass  
{  
    [ImportMany]  
    public IEnumerable<IMyAddin> MyAddin { get; set; }  
}  

È possibile accedere alla matrice importata usando la normale sintassi e i normali metodi di IEnumerable<T> .The imported array can be accessed by using ordinary IEnumerable<T> syntax and methods. È anche possibile usare invece una matrice normale (IMyAddin[]).It is also possible to use an ordinary array (IMyAddin[]) instead.

Questo modello può risultare molto importante se lo si usa insieme alla sintassi Lazy<T> .This pattern can be very important when you use it in combination with the Lazy<T> syntax. Ad esempio, se si usa ImportMany, IEnumerable<T>e Lazy<T>, sarà possibile importare riferimenti indiretti a qualsiasi numero di oggetti e creare istanze solo degli oggetti che diventano necessari.For example, by using ImportMany, IEnumerable<T>, and Lazy<T>, you can import indirect references to any number of objects and only instantiate the ones that become necessary. Questo modello è illustrato dalla classe seguente.The following class shows this pattern.

Public Class MyClass1  

    <ImportMany()>  
    Public Property MyAddin As IEnumerable(Of Lazy(Of IMyAddin))  

End Class  
public class MyClass  
{  
    [ImportMany]  
    public IEnumerable<Lazy<IMyAddin>> MyAddin { get; set; }  
}  

Evitare l'individuazioneAvoiding Discovery

In alcuni casi è possibile che si voglia evitare l'individuazione di una parte come parte di un catalogo.In some cases, you may want to prevent a part from being discovered as part of a catalog. Ad esempio, è possibile che la parte sia una classe di base da cui ereditare, ma da non usare.For example, the part may be a base class intended to be inherited from, but not used. È possibile ottenere questo risultato in due modi.There are two ways to accomplish this. Si può prima di tutto usare la parola chiave abstract nella classe della parte.First, you can use the abstract keyword on the part class. Le classi astratte non forniscono mai esportazioni, anche se possono fornire esportazioni ereditate alle classi da esse derivate.Abstract classes never provide exports, although they can provide inherited exports to classes that derive from them.

Se non è possibile rendere astratta la classe, sarà possibile decorarla con l'attributo PartNotDiscoverable .If the class cannot be made abstract, you can decorate it with the PartNotDiscoverable attribute. Una parte decorata con questo attributo non sarà inclusa in alcun catalogo.A part decorated with this attribute will not be included in any catalogs. L'esempio seguente illustra questi modelli.The following example demonstrates these patterns. DataOne sarà individuata dal catalogo.DataOne will be discovered by the catalog. Poiché DataTwo è astratta, non sarà individuata.Since DataTwo is abstract, it will not be discovered. Poiché DataThree ha usato l'attributo PartNotDiscoverable , non sarà individuata.Since DataThree used the PartNotDiscoverable attribute, it will not be discovered.

<Export()>  
Public Class DataOne  
    'This part will be discovered   
    'as normal by the catalog.  
End Class  

<Export()>  
Public MustInherit Class DataTwo  
    'This part will not be discovered  
    'by the catalog.  
End Class  

<PartNotDiscoverable()>  
<Export()>  
Public Class DataThree  
    'This part will also not be discovered  
    'by the catalog.  
End Class  
[Export]  
public class DataOne  
{  
    //This part will be discovered  
    //as normal by the catalog.  
}  

[Export]  
public abstract class DataTwo  
{  
    //This part will not be discovered  
    //by the catalog.  
}  

[PartNotDiscoverable]  
[Export]  
public class DataThree  
{  
    //This part will also not be discovered  
    //by the catalog.  
}  

Metadati e viste dei metadatiMetadata and Metadata Views

Le esportazioni possono fornire informazioni aggiuntive su se stesse, definite metadati.Exports can provide additional information about themselves known as metadata. I metadati possono essere usati per trasmettere le proprietà dell'oggetto esportato alla parte che esegue l'importazione.Metadata can be used to convey properties of the exported object to the importing part. La parte che esegue l'importazione può usare questi dati per decidere quali esportazioni usare oppure per ottenere informazioni su un'esportazione senza doverla costruire.The importing part can use this data to decide which exports to use, or to gather information about an export without having to construct it. Per questo motivo, un'importazione deve essere differita per usare i metadati.For this reason, an import must be lazy to use metadata.

Per usare i metadati si dichiara in genere un'interfaccia definita vista dei metadati, in cui sono dichiarati i metadati che saranno disponibili.To use metadata, you typically declare an interface known as a metadata view, which declares what metadata will be available. L'interfaccia della vista dei metadati deve includere solo proprietà e queste proprietà devono avere get funzioni di accesso.The metadata view interface must have only properties, and those properties must have get accessors. L'interfaccia seguente è un esempio di vista dei metadati.The following interface is an example metadata view.

Public Interface IPluginMetadata  

    ReadOnly Property Name As String  

    <DefaultValue(1)>  
    ReadOnly Property Version As Integer  

End Interface  
public interface IPluginMetadata  
{  
    string Name { get; }  

    [DefaultValue(1)]    
    int Version { get; }  
}  

È anche possibile usare una raccolta generica, IDictionary<string, object>, come vista dei metadati, ma in questo modo non saranno disponibili i vantaggi correlati alla verifica dei tipi e questa procedura è quindi sconsigliata.It is also possible to use a generic collection, IDictionary<string, object>, as a metadata view, but this forfeits the benefits of type checking and should be avoided.

In genere, tutte le proprietà indicate nella vista dei metadati sono necessarie ed eventuali esportazioni che non le forniscono non saranno considerate come corrispondenze.Ordinarily, all of the properties named in the metadata view are required, and any exports that do not provide them will not be considered a match. L'attributo DefaultValue specifica che una proprietà è facoltativa.The DefaultValue attribute specifies that a property is optional. Se non è inclusa, alla proprietà sarà assegnato il valore predefinito specificato come parametro di DefaultValue.If the property is not included, it will be assigned the default value specified as a parameter of DefaultValue. Di seguito sono riportate due classi diverse decorate con metadati.The following are two different classes decorated with metadata. Entrambe le classi corrisponderebbero alla vista dei metadati precedente.Both of these classes would match the previous metadata view.

<Export(GetType(IPlugin))>  
<ExportMetadata("Name", "Logger")>  
<ExportMetadata("Version", 4)>  
Public Class MyLogger  
    Implements IPlugin  

End Class  

'Version is not required because of the DefaultValue  
<Export(GetType(IPlugin))>  
<ExportMetadata("Name", "Disk Writer")>  
Public Class DWriter  
    Implements IPlugin  

End Class  
[Export(typeof(IPlugin)),  
    ExportMetadata("Name", "Logger"),  
    ExportMetadata("Version", 4)]  
public class Logger : IPlugin  
{  
}  

[Export(typeof(IPlugin)),  
    ExportMetadata("Name", "Disk Writer")]   
    //Version is not required because of the DefaultValue  
public class DWriter : IPlugin  
{  
}  

I metadati sono espressi dopo l'attributo Export tramite l'attributo ExportMetadata .Metadata is expressed after the Export attribute by using the ExportMetadata attribute. Ogni elemento di metadati è costituito da una coppia nome/valore.Each piece of metadata is composed of a name/value pair. La parte relativa al nome dei metadati deve corrispondere al nome della proprietà appropriata nella vista dei metadati e il valore sarà assegnato a tale proprietà.The name portion of the metadata must match the name of the appropriate property in the metadata view, and the value will be assigned to that property.

L'utilità di importazione specifica l'eventuale vista dei metadati che sarà usata.It is the importer that specifies what metadata view, if any, will be in use. Un'importazione con metadati è dichiarata come importazione differita, con l'interfaccia dei metadati come parametro di secondo tipo per Lazy<T,T>.An import with metadata is declared as a lazy import, with the metadata interface as the second type parameter to Lazy<T,T>. La classe seguente importa la parte precedente con i metadati.The following class imports the previous part with metadata.

Public Class Addin  

    <Import()>  
    Public Property plugin As Lazy(Of IPlugin, IPluginMetadata)  
End Class  
public class Addin  
{  
    [Import]  
    public Lazy<IPlugin, IPluginMetadata> plugin;  
}  

In molti casi è consigliabile combinare i metadati con l'attributo ImportMany , in modo da analizzare le importazioni disponibili e scegliere e creare istanze di una sola importazione oppure per filtrare una raccolta in modo che corrisponda a una determinata condizione.In many cases, you will want to combine metadata with the ImportMany attribute, in order to parse through the available imports and choose and instantiate only one, or filter a collection to match a certain condition. La classe seguente crea istanze dei soli oggetti IPlugin con valore Name impostato su "Logger".The following class instantiates only IPlugin objects that have the Name value "Logger".

Public Class User  

    <ImportMany()>  
    Public Property plugins As IEnumerable(Of Lazy(Of IPlugin, IPluginMetadata))  

    Public Function InstantiateLogger() As IPlugin  

        Dim logger As IPlugin  
        logger = Nothing  

        For Each Plugin As Lazy(Of IPlugin, IPluginMetadata) In plugins  
            If (Plugin.Metadata.Name = "Logger") Then  
                logger = Plugin.Value  
            End If  
        Next  
        Return logger  
    End Function  

End Class  
public class User  
{  
    [ImportMany]  
    public IEnumerable<Lazy<IPlugin, IPluginMetadata>> plugins;  

    public IPlugin InstantiateLogger ()  
    {  
        IPlugin logger = null;  

        foreach (Lazy<IPlugin, IPluginMetadata> plugin in plugins)  
        {  
            if (plugin.Metadata.Name = "Logger") logger = plugin.Value;  
        }  
        return logger;  
    }  
}  

Eredità di importazione ed esportazioneImport and Export Inheritance

Se una classe eredita da una parte, anche tale classe può diventare una parte.If a class inherits from a part, that class may also become a part. Le importazioni sono sempre ereditate dalle sottoclassi.Imports are always inherited by subclasses. Una sottoclasse di una parte, quindi, sarà sempre una parte, con le stesse importazioni come classe padre.Therefore, a subclass of a part will always be a part, with the same imports as its parent class.

Le esportazioni dichiarate usando l'attributo Export non sono ereditate dalle sottoclassi.Exports declared by using the Export attribute are not inherited by subclasses. Una parte, tuttavia, può esportare se stessa usando l'attributo InheritedExport .However, a part can export itself by using the InheritedExport attribute. Le sottoclassi della parte erediteranno e forniranno la stessa esportazione, inclusi nome e tipo di contratto.Subclasses of the part will inherit and provide the same export, including contract name and contract type. A differenza di un attributo Export , InheritedExport può essere applicato solo a livello di classe, non a livello di membro.Unlike an Export attribute, InheritedExport can be applied only at the class level, and not at the member level. Le esportazioni a livello di membri non possono quindi essere mai ereditate.Therefore, member-level exports can never be inherited.

Le quattro classi seguenti illustrano i principi dell'ereditarietà di importazione ed esportazione.The following four classes demonstrate the principles of import and export inheritance. NumTwo eredita da NumOne, quindi NumTwo importerà IMyData.NumTwo inherits from NumOne, so NumTwo will import IMyData. Le esportazioni normali non sono ereditate, quindi NumTwo non esporterà nulla.Ordinary exports are not inherited, so NumTwo will not export anything. NumFour eredita da NumThree.NumFour inherits from NumThree. Poiché NumThree ha usato InheritedExport, NumFour ha un'esportazione con tipo di contratto NumThree.Because NumThree used InheritedExport, NumFour has one export with contract type NumThree. Le esportazioni a livello di membri non sono mai ereditate, quindi IMyData non viene esportato.Member-level exports are never inherited, so IMyData is not exported.

<Export()>  
Public Class NumOne  
    <Import()>  
    Public Property MyData As IMyData  
End Class  

Public Class NumTwo  
    Inherits NumOne  

    'Imports are always inherited, so NumTwo will  
    'Import IMyData  

    'Ordinary exports are not inherited, so  
    'NumTwo will NOT export anything.  As a result it  
    'will not be discovered by the catalog!  

End Class  

<InheritedExport()>  
Public Class NumThree  

    <Export()>  
    Public Property MyData As IMyData  

    'This part provides two exports, one of  
    'contract type NumThree, and one of   
    'contract type IMyData.  

End Class  

Public Class NumFour  
    Inherits NumThree  

    'Because NumThree used InheritedExport,  
    'this part has one export with contract   
    'type NumThree.  

    'Member-level exports are never inherited,  
    'so IMyData is not exported.  

End Class  
[Export]  
public class NumOne  
{  
    [Import]  
    public IMyData MyData { get; set; }  
}  

public class NumTwo : NumOne  
{  
    //Imports are always inherited, so NumTwo will   
    //import IMyData.  

    //Ordinary exports are not inherited, so   
    //NumTwo will NOT export anything. As a result it   
    //will not be discovered by the catalog!  
}  

[InheritedExport]  
public class NumThree  
{  
    [Export]  
    Public IMyData MyData { get; set; }  

    //This part provides two exports, one of  
    //contract type NumThree, and one of  
    //contract type IMyData.  
}  

public class NumFour : NumThree  
{  
    //Because NumThree used InheritedExport,  
    //this part has one export with contract  
    //type NumThree.  

    //Member-level exports are never inherited,  
    //so IMyData is not exported.  
}  

Se a un attributo InheritedExport sono associati metadati, anche i metadati saranno ereditati.If there is metadata associated with an InheritedExport attribute, that metadata will also be inherited. Per altre informazioni, vedere la sezione precedente "Metadati e viste dei metadati". I metadati ereditati non possono essere modificati dalla sottoclasse.(For more information, see the earlier "Metadata and Metadata Views" section.) Inherited metadata cannot be modified by the subclass. Dichiarando di nuovo l'attributo InheritedExport con lo stesso nome e tipo di contratto ma con nuovi metadati, tuttavia, la sottoclasse potrà sostituire i metadati ereditati con nuovi metadati.However, by re-declaring the InheritedExport attribute with the same contract name and contract type, but with new metadata, the subclass can replace the inherited metadata with new metadata. La classe seguente illustra questo principio.The following class demonstrates this principle. La parte MegaLogger eredita da Logger e include l'attributo InheritedExport .The MegaLogger part inherits from Logger and includes the InheritedExport attribute. Poiché MegaLogger ripete la dichiarazione di nuovi metadati con nome Status, non erediterà i metadati Name e Version da Logger.Since MegaLogger re-declares new metadata named Status, it does not inherit the Name and Version metadata from Logger.

<InheritedExport(GetType(IPlugin))>  
<ExportMetadata("Name", "Logger")>  
<ExportMetadata("Version", 4)>  
Public Class Logger  
    Implements IPlugin  

    'Exports with contract type IPlugin  
    'and metadata "Name" and "Version".  
End Class  

Public Class SuperLogger  
    Inherits Logger  

    'Exports with contract type IPlugin and   
    'metadata "Name" and "Version", exactly the same  
    'as the Logger class.  

End Class  

<InheritedExport(GetType(IPlugin))>  
<ExportMetadata("Status", "Green")>  
Public Class MegaLogger  
    Inherits Logger  

    'Exports with contract type IPlugin and   
    'metadata "Status" only. Re-declaring   
    'the attribute replaces all metadata.  

End Class  
[InheritedExport(typeof(IPlugin)),  
    ExportMetadata("Name", "Logger"),  
    ExportMetadata("Version", 4)]  
public class Logger : IPlugin  
{  
    //Exports with contract type IPlugin and   
    //metadata "Name" and "Version".  
}  

public class SuperLogger : Logger  
{  
    //Exports with contract type IPlugin and   
    //metadata "Name" and "Version", exactly the same  
    //as the Logger class.  
}  

[InheritedExport(typeof(IPlugin)),  
    ExportMetadata("Status", "Green")]  
public class MegaLogger : Logger        {  
    //Exports with contract type IPlugin and   
    //metadata "Status" only. Re-declaring   
    //the attribute replaces all metadata.  
}  

Quando si dichiara di nuovo l'attributo InheritedExport per eseguire l'override dei metadati, occorre assicurarsi che i tipi di contratto siano uguali.When re-declaring the InheritedExport attribute to override metadata, make sure that the contract types are the same. Nell'esempio precedente, IPlugin è il tipo di contratto In caso di differenza, invece di eseguire l'override, il secondo attributo creerà una seconda esportazione indipendente dalla parte.(In the previous example, IPlugin is the contract type.) If they differ, instead of overriding, the second attribute will create a second, independent export from the part. In genere, ciò significa che sarà necessario specificare in modo esplicito il tipo di contratto quando si esegue l'override di un attributo InheritedExport, come illustrato nell'esempio precedente.Generally, this means that you will have to explicitly specify the contract type when you override an InheritedExport attribute, as shown in the previous example.

Poiché non è possibile creare direttamente istanze delle interfacce, non è in genere possibile decorarle con attributi Export o Import .Since interfaces cannot be instantiated directly, they generally cannot be decorated with Export or Import attributes. Un'interfaccia può essere tuttavia decorata con l'attributo InheritedExport a livello di interfaccia e tale esportazione, insieme a eventuali metadati associati, sarà ereditata da qualsiasi classe che esegue l'implementazione.However, an interface can be decorated with an InheritedExport attribute at the interface level, and that export along with any associated metadata will be inherited by any implementing classes. L'interfaccia stessa, tuttavia, non sarà disponibile come parte.The interface itself will not be available as a part, however.

Attributi di esportazione personalizzatiCustom Export Attributes

Gli attributi di esportazione di base, Export e InheritedExport, possono essere estesi in modo da includere metadati come proprietà degli attributi.The basic export attributes, Export and InheritedExport, can be extended to include metadata as attribute properties. Questa tecnica è utile per l'applicazione di metadati simili a molte parti oppure per creare un albero di eredità di attributi di metadati.This technique is useful for applying similar metadata to many parts, or creating an inheritance tree of metadata attributes.

Un attributo personalizzato può specificare il tipo di contratto, il nome del contratto o altri metadati.A custom attribute can specify the contract type, the contract name, or any other metadata. Per definire un attributo personalizzato, una classe che eredita da ExportAttribute (o InheritedExportAttribute) deve essere decorata con l'attributo MetadataAttribute .In order to define a custom attribute, a class inheriting from ExportAttribute (or InheritedExportAttribute) must be decorated with the MetadataAttribute attribute. La classe seguente definisce un attributo personalizzato.The following class defines a custom attribute.

<MetadataAttribute()>  
<AttributeUsage(AttributeTargets.Class, AllowMultiple:=false)>  
Public Class MyAttribute  
    Inherits ExportAttribute  

    Public Property MyMetadata As String  

    Public Sub New(ByVal myMetadata As String)  
        MyBase.New(GetType(IMyAddin))  

        myMetadata = myMetadata  
    End Sub  

End Class  
[MetadataAttribute]  
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]  
public class MyAttribute : ExportAttribute  
{  
    public MyAttribute(string myMetadata)   
        : base(typeof(IMyAddin))  
    {  
        MyMetadata = myMetadata;  
    }  

    public string MyMetadata { get; private set; }  
}  

Questa classe definisce un attributo personalizzato denominato MyAttribute con tipo di contratto IMyData e alcuni metadati con nome MyMetadata.This class defines a custom attribute named MyAttribute with contract type IMyData and some metadata named MyMetadata. Tutte le proprietà in una classe contrassegnata con l'attributo MetadataAttribute sono considerate come metadati definiti nell'attributo personalizzato.All properties in a class marked with the MetadataAttribute attribute are considered to be metadata defined in the custom attribute. Le due dichiarazioni seguenti sono equivalenti.The following two declarations are equivalent.

<Export(GetType(IMyAddin))>  
<ExportMetadata("MyMetadata", "theData")>  
Public Property myAddin As MyAddin  

<MyAttribute("theData")>  
Public Property myAddin As MyAddin  
[Export(typeof(IMyAddin)),   
    ExportMetadata("MyMetadata", "theData")]  
public MyAddin myAddin { get; set; }  
[MyAttribute("theData")]  
public MyAddin myAddin { get; set; }  

Nella prima dichiarazione il tipo di contratto e i metadati sono definiti in modo esplicito.In the first declaration, the contract type and metadata are explicitly defined. Nella seconda dichiarazione il tipo di contratto e i metadati sono impliciti nell'attributo personalizzato.In the second declaration, the contract type and metadata are implicit in the customized attribute. In particolare nei casi in cui è necessario applicare una quantità elevata di metadati identici a molte parti, ad esempio informazioni su autore o copyright, l'uso di un attributo personalizzato può permettere un notevole risparmio di tempo e di duplicazione.Particularly in cases where a large amount of identical metadata must be applied to many parts (for example, author or copyright information), using a custom attribute can save a lot of time and duplication. Gli alberi di eredità degli attributi personalizzati, inoltre, possono essere creati in modo da permettere variazioni.Further, inheritance trees of custom attributes can be created to allow for variations.

Per creare metadati facoltativi in un attributo personalizzato, è possibile usare l'attributo DefaultValue .To create optional metadata in a custom attribute, you can use the DefaultValue attribute. Quando questo attributo è applicato a una proprietà in una classe di attributi personalizzata, specifica che la proprietà decorata è facoltativa e non deve essere fornita da un'utilità di esportazione.When this attribute is applied to a property in a custom attribute class, it specifies that the decorated property is optional and does not have to be supplied by an exporter. Se un valore per la proprietà non è stato fornito, sarà assegnato il valore predefinito per questo tipo di proprietà, in genere null, falseo 0.If a value for the property is not supplied, it will be assigned the default value for its property type (usually null, false, or 0.)

Criteri di creazioneCreation Policies

Quando una parte specifica un'importazione e si esegue una composizione, il contenitore di composizione tenta di trovare un'esportazione corrispondente.When a part specifies an import and composition is performed, the composition container attempts to find a matching export. In caso di corretta corrispondenza tra importazione ed esportazione, il membro che esegue l'importazione è impostato su un'istanza dell'oggetto esportato.If it matches the import with an export successfully, the importing member is set to an instance of the exported object. La provenienza di questa istanza è controllata dai criteri di creazionedella parte che esegue l'esportazione.Where this instance comes from is controlled by the exporting part's creation policy.

I due criteri di creazione consentiti sono condivisi e non condivisi.The two possible creation policies are shared and non-shared. Una parte con criteri di creazione condivisi sarà condivisa tra tutte le importazioni nel contenuto per una parte con tale contratto.A part with a creation policy of shared will be shared between every import in the container for a part with that contract. Quando il motore della composizione rileva una corrispondenza e deve impostare una proprietà che esegue l'importazione, crea un'istanza di una nuova copia della parte solo se non esiste già. In caso contrario, fornisce la copia esistente.When the composition engine finds a match and has to set an importing property, it will instantiate a new copy of the part only if one does not already exist; otherwise, it will supply the existing copy. Ciò significa che molti oggetti potrebbero includere riferimenti alla stessa parte.This means that many objects may have references to the same part. È quindi consigliabile che queste parti non si basino su uno stato interno che potrebbe subire modifiche da molte posizioni.Such parts should not rely on internal state that might be changed from many places. Questi criteri sono appropriati per parti statiche, parti che offrono servizi e parti che usano una quantità elevata di memoria o di risorse di altro tipo.This policy is appropriate for static parts, parts that provide services, and parts that consume a lot of memory or other resources.

Una parte con criteri di creazione non condivisi sarà creata ogni volta che è rilevata un'importazione corrispondente per una delle esportazioni della parte.A part with the creation policy of non-shared will be created every time a matching import for one of its exports is found. Sarà quindi creata un'istanza della nuova copia per ogni importazione nel contenitore corrispondente a uno dei contratti esportati della parte.A new copy will therefore be instantiated for every import in the container that matches one of the part's exported contracts. Lo stato interno di queste copie non sarà condiviso.The internal state of these copies will not be shared. Questi criteri sono appropriati per parti in cui ogni importazione necessita del proprio stato interno.This policy is appropriate for parts where each import requires its own internal state.

Sia l'importazione che l'esportazione possono specificare i criteri di creazione di una parte, scegliendo tra i valori Shared, NonSharedo Any.Both the import and the export can specify the creation policy of a part, from among the values Shared, NonShared, or Any. Il valore predefinito è Any sia per le importazioni che per le esportazioni.The default is Any for both imports and exports. Un'esportazione che specifica Shared o NonShared corrisponderà solo a un'importazione che specifica lo stesso valore o che specifica Any.An export that specifies Shared or NonShared will only match an import that specifies the same, or that specifies Any. Analogamente, un'importazione che specifica Shared o NonShared corrisponderà solo a un'esportazione che specifica lo stesso valore o che specifica Any.Similarly, an import that specifies Shared or NonShared will only match an export that specifies the same, or that specifies Any. Le importazioni e le esportazioni con criteri di creazione non compatibili non saranno considerate come corrispondenti, esattamente come non lo sono un'importazione e un'esportazione con tipo o nome di contratto non corrispondenti.Imports and exports with incompatible creation policies are not considered a match, in the same way as an import and export whose contract name or contract type are not a match. Se sia l'importazione che l'esportazione specificano Anyo non specificano alcun criterio di creazione e usano il valore predefinito Any, i criteri di creazione saranno condivisi per impostazione predefinita.If both import and export specify Any, or do not specify a creation policy and default to Any, the creation policy will default to shared.

L'esempio seguente mostra sia le importazioni che le esportazioni che specificano criteri di creazione.The following example shows both imports and exports specifying creation policies. PartOne non specifica alcun criterio di creazione, quindi l'impostazione predefinita è Any.PartOne does not specify a creation policy, so the default is Any. PartTwo non specifica alcun criterio di creazione, quindi l'impostazione predefinita è Any.PartTwo does not specify a creation policy, so the default is Any. Poiché sia per l'importazione che per l'esportazione sarà usato il valore predefinito Any, PartOne sarà condivisa.Since both import and export default to Any, PartOne will be shared. PartThree specifica un criterio di creazione Shared , quindi PartTwo e PartThree condivideranno la stessa copia di PartOne.PartThree specifies a Shared creation policy, so PartTwo and PartThree will share the same copy of PartOne. PartFour specifica un criterio di creazione NonShared , quindi PartFour non saranno condivisi in PartFive.PartFour specifies a NonShared creation policy, so PartFour will be non-shared in PartFive. PartSix specifica un criterio di creazione NonShared .PartSix specifies a NonShared creation policy. PartFive e PartSix riceveranno copie distinte di PartFour.PartFive and PartSix will each receive separate copies of PartFour. PartSeven specifica un criterio di creazione Shared .PartSeven specifies a Shared creation policy. Poiché non è disponibile alcuna PartFour esportata con un criterio di creazione Shared, l'importazione PartSeven non corrisponde a nessun elemento e non sarà completata.Because there is no exported PartFour with a creation policy of Shared, the PartSeven import does not match anything and will not be filled.

<Export()>  
Public Class PartOne  
    'The default creation policy for an export is Any.  
End Class  

Public Class PartTwo  

    <Import()>  
    Public Property partOne As PartOne  

    'The default creation policy for an import is Any.  
    'If both policies are Any, the part will be shared.  

End Class  

Public Class PartThree  

    <Import(RequiredCreationPolicy:=CreationPolicy.Shared)>  
    Public Property partOne As PartOne  

    'The Shared creation policy is explicitly specified.  
    'PartTwo and PartThree will receive references to the  
    'SAME copy of PartOne.  

End Class  

<Export()>  
<PartCreationPolicy(CreationPolicy.NonShared)>  
Public Class PartFour  
    'The NonShared creation policy is explicitly specified.  
End Class  

Public Class PartFive  

    <Import()>  
    Public Property partFour As PartFour  

    'The default creation policy for an import is Any.  
    'Since the export's creation policy was explictly  
    'defined, the creation policy for this property will  
    'be non-shared.  

End Class  

Public Class PartSix  

    <Import(RequiredCreationPolicy:=CreationPolicy.NonShared)>  
    Public Property partFour As PartFour  

    'Both import and export specify matching creation   
    'policies.  PartFive and PartSix will each receive   
    'SEPARATE copies of PartFour, each with its own  
    'internal state.  

End Class  

Public Class PartSeven  

    <Import(RequiredCreationPolicy:=CreationPolicy.Shared)>  
    Public Property partFour As PartFour  

    'A creation policy mismatch.  Because there is no   
    'exported PartFour with a creation policy of Shared,  
    'this import does not match anything and will not be  
    'filled.  

End Class  
[Export]  
public class PartOne  
{  
    //The default creation policy for an export is Any.  
}  

public class PartTwo  
{  
    [Import]  
    public PartOne partOne { get; set; }  

    //The default creation policy for an import is Any.  
    //If both policies are Any, the part will be shared.  
}  

public class PartThree  
{  
    [Import(RequiredCreationPolicy = CreationPolicy.Shared)]  
    public PartOne partOne { get; set; }  

    //The Shared creation policy is explicitly specified.  
    //PartTwo and PartThree will receive references to the  
    //SAME copy of PartOne.  
}  

[Export]  
[PartCreationPolicy(CreationPolicy.NonShared)]  
public class PartFour  
{  
    //The NonShared creation policy is explicitly specified.  
}  

public class PartFive  
{  
    [Import]  
    public PartFour partFour { get; set; }  

    //The default creation policy for an import is Any.  
    //Since the export's creation policy was explictly  
    //defined, the creation policy for this property will  
    //be non-shared.  
}  

public class PartSix  
{  
    [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]  
    public PartFour partFour { get; set; }  

    //Both import and export specify matching creation   
    //policies.  PartFive and PartSix will each receive   
    //SEPARATE copies of PartFour, each with its own  
    //internal state.  
}  

public class PartSeven  
{  
    [Import(RequiredCreationPolicy = CreationPolicy.Shared)]  
    public PartFour partFour { get; set; }  

    //A creation policy mismatch.  Because there is no   
    //exported PartFour with a creation policy of Shared,  
    //this import does not match anything and will not be  
    //filled.  
}  

Ciclo di vita ed eliminazioneLife Cycle and Disposing

Poiché le parti sono ospitate nel contenitore di composizione, il relativo ciclo di vita può essere più complesso rispetto a quello degli oggetti normali.Because parts are hosted in the composition container, their life cycle can be more complex than ordinary objects. Le parti possono implementare due interfacce importanti correlate al ciclo di vita, ovvero IDisposable e IPartImportsSatisfiedNotification.Parts can implement two important life cycle-related interfaces: IDisposable and IPartImportsSatisfiedNotification.

Le parti che necessitano dell'esecuzione di operazioni in fase di arresto o del rilascio di risorse devono implementare IDisposable, come di consueto per oggetti .NET Framework.Parts that require work to be performed at shut down or that need to release resources should implement IDisposable, as usual for .NET Framework objects. Poiché tuttavia il contenitore crea e gestisce riferimenti alle parti, solo il contenitore proprietario di una parte dovrebbe chiamare il metodo Dispose per tale parte.However, since the container creates and maintains references to parts, only the container that owns a part should call the Dispose method on it. Il contenitore stesso implementa IDisposablee come parte della pulizia in Dispose chiamerà Dispose per tutte le parti di sua proprietà.The container itself implements IDisposable, and as portion of its cleanup in Dispose it will call Dispose on all the parts that it owns. Per questo motivo, è sempre consigliabile eliminare il contenitore di composizione quando il contenitore ed eventuali parti di sua proprietà non sono più necessari.For this reason, you should always dispose the composition container when it and any parts it owns are no longer needed.

Per i contenitori di composizione di lunga durata, il consumo di memoria da parte delle parti con criteri di creazione non condivisi può rappresentare un problema.For long-lived composition containers, memory consumption by parts with a creation policy of non-shared can become a problem. Le parti non condivise possono essere create più volte e saranno eliminate solo quando si elimina il contenitore stesso.These non-shared parts can be created multiple times and will not be disposed until the container itself is disposed. Per risolvere questo problema, il contenitore fornisce il metodo ReleaseExport .To deal with this, the container provides the ReleaseExport method. Se si chiama questo metodo in un'esportazione non condivisa, tale esportazione sarà rimossa dal contenitore di composizione e sarà eliminata.Calling this method on a non-shared export removes that export from the composition container and disposes it. Saranno rimosse ed eliminate anche le parti usate solo dall'esportazione rimossa e così via lungo l'albero.Parts that are used only by the removed export, and so on down the tree, are also removed and disposed. In questo modo sarà possibile recuperare le risorse senza eliminare il contenitore di composizione.In this way, resources can be reclaimed without disposing the composition container itself.

IPartImportsSatisfiedNotification include un metodo con nome OnImportsSatisfied.IPartImportsSatisfiedNotification contains one method named OnImportsSatisfied. Questo metodo è chiamato dal contenitore di composizione per qualsiasi parte che implementa l'interfaccia quando la composizione è stata completata e le importazioni della parte sono pronte per l'uso.This method is called by the composition container on any parts that implement the interface when composition has been completed and the part's imports are ready for use. Le parti sono create dal motore di composizione per completare le importazioni di altre parti.Parts are created by the composition engine to fill the imports of other parts. Prima dell'impostazione delle importazioni di una parte, sarà possibile eseguire inizializzazioni che si basano su o che modificano valori importati nel costruttore della parte solo se tali valori sono stati specificati come prerequisiti usando l'attributo ImportingConstructor .Before the imports of a part have been set, you cannot perform any initialization that relies on or manipulates imported values in the part constructor unless those values have been specified as prerequisites by using the ImportingConstructor attribute. Questo è in genere il metodo preferito, ma in alcuni casi è possibile che l'aggiunta di costruttori non sia disponibile.This is normally the preferred method, but in some cases, constructor injection may not be available. In questi casi l'inizializzazione può essere eseguita in OnImportsSatisfiede la parte deve implementare IPartImportsSatisfiedNotification.In those cases, initialization can be performed in OnImportsSatisfied, and the part should implement IPartImportsSatisfiedNotification.

Vedere ancheSee Also

Video Channel 9: Aprire le applicazioni con Managed Extensibility FrameworkChannel 9 Video: Open Up Your Applications with the Managed Extensibility Framework
Video Channel 9: Managed Extensibility Framework (MEF) 2.0Channel 9 Video: Managed Extensibility Framework (MEF) 2.0