diff options
author | Marek Safar <marek.safar@gmail.com> | 2011-11-02 15:17:33 +0400 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2011-11-03 16:08:02 +0400 |
commit | b071c20379abeee79086ee57663f81c4c5626ce7 (patch) | |
tree | 4885af5c4b579086b42325ea4611622402275a44 /mcs/class/System.ComponentModel.Composition.4.5/src | |
parent | 39538a54aa230a60d2cfbca491e02bcda8b7c07b (diff) |
Add 4.5 compatible MEF
Diffstat (limited to 'mcs/class/System.ComponentModel.Composition.4.5/src')
181 files changed, 26870 insertions, 0 deletions
diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/Assembly/AssemblyInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/Assembly/AssemblyInfo.cs new file mode 100644 index 00000000000..a1cceccbcd3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/Assembly/AssemblyInfo.cs @@ -0,0 +1,62 @@ +// +// AssemblyInfo.cs +// +// Authors: +// Marek Safar (marek.safar@gmail.com) +// +// Copyright 2011 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using System.Resources; +using System.Security; +using System.Security.Permissions; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about the assembly + +[assembly: AssemblyTitle ("System.ComponentModel.Composition.dll")] +[assembly: AssemblyDescription ("System.ComponentModel.Composition.dll")] +[assembly: AssemblyDefaultAlias ("System.ComponentModel.Composition.dll")] + +[assembly: AssemblyCompany (Consts.MonoCompany)] +[assembly: AssemblyProduct (Consts.MonoProduct)] +[assembly: AssemblyCopyright("(c) Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyVersion (Consts.FxVersion)] +[assembly: SatelliteContractVersion (Consts.FxVersion)] +[assembly: AssemblyInformationalVersion (Consts.FxFileVersion)] +[assembly: AssemblyFileVersion (Consts.FxFileVersion)] + +[assembly: NeutralResourcesLanguage ("en-US")] +[assembly: CLSCompliant (true)] +[assembly: AssemblyDelaySign (true)] + +[assembly: AssemblyKeyFile ("../ecma.pub")] + +[assembly: SecurityCritical] +[assembly: AllowPartiallyTrustedCallers] +[assembly: ComVisible (false)] + + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/AssemblyInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/AssemblyInfo.cs new file mode 100644 index 00000000000..ca473df0e3b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/AssemblyInfo.cs @@ -0,0 +1,26 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Runtime.CompilerServices; +using System.Security; + +#if FEATURE_CAS_APTCA +[assembly: AllowPartiallyTrustedCallers] +#endif //FEATURE_CAS_APTCA + +#if USE_CUSTOM_KEY +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000fc5993e0f511ad5e16e8b226553493e09067afc41039f70daeb94a968d664f40e69a46b617d15d3d5328be7dbedd059eb98495a3b03cb4ea4ba127444671c3c84cbc1fdc393d7e10b5ee3f31f5a29f005e5eed7e3c9c8af74f413f0004f0c2cabb22f9dd4f75a6f599784e1bab70985ef8174ca6c684278be82ce055a03ebaf")] +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTestFramework, PublicKey=00240000048000009400000006020000002400005253413100040000010001000fc5993e0f511ad5e16e8b226553493e09067afc41039f70daeb94a968d664f40e69a46b617d15d3d5328be7dbedd059eb98495a3b03cb4ea4ba127444671c3c84cbc1fdc393d7e10b5ee3f31f5a29f005e5eed7e3c9c8af74f413f0004f0c2cabb22f9dd4f75a6f599784e1bab70985ef8174ca6c684278be82ce055a03ebaf")] +#elif USE_SILVERLIGHT_KEY +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")] +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTestFramework, PublicKey=0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9")] +#elif USE_ECMA_KEY +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTests, PublicKey=00000000000000000400000000000000")] +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTestFramework, PublicKey=00000000000000000400000000000000")] +#elif USE_CODEPLEX_KEY +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTests.CodePlex, PublicKey=0024000004800000940000000602000000240000525341310004000001000100616470ad6a034af669d130b58deedb7ad8544920d8a21d95bc5bb535ca673d8a49b228c5163f78f34b8df3b015fc2b99ff45b7536830a596f711b8b09f80b48a4bf20883ee5b97f50462d7e0f33440f024dae7d8f7eaf875b747619f1e772131a24dea9d5f80e5d54d95f0704f78fe84ac4b3774ce17eb00a764c295846d43e3")] +[assembly: InternalsVisibleTo("System.ComponentModel.Composition.UnitTestFramework.CodePlex, PublicKey=0024000004800000940000000602000000240000525341310004000001000100616470ad6a034af669d130b58deedb7ad8544920d8a21d95bc5bb535ca673d8a49b228c5163f78f34b8df3b015fc2b99ff45b7536830a596f711b8b09f80b48a4bf20883ee5b97f50462d7e0f33440f024dae7d8f7eaf875b747619f1e772131a24dea9d5f80e5d54d95f0704f78fe84ac4b3774ce17eb00a764c295846d43e3")] +#else +#error Unknown platform +#endif
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/CodePlexKey.snk b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/CodePlexKey.snk Binary files differnew file mode 100644 index 00000000000..5d44ffe878f --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/CodePlexKey.snk diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/ComponentModel.csproj b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/ComponentModel.csproj new file mode 100644 index 00000000000..bafafb2d6c4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/ComponentModel.csproj @@ -0,0 +1,250 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+ <PropertyGroup>
+ <ProductVersion>10.0.20729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{1BBA5101-D4F0-48B8-A5D6-7B23A099DCE3}</ProjectGuid>
+ <ProjectTypeGuids></ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AssemblyName>System.ComponentModel.Composition.CodePlex</AssemblyName>
+ <RootNamespace>Microsoft.Internal</RootNamespace>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+</PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\build\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;CLR40;USE_CODEPLEX_KEY;FEATURE_LEGACYSURFACEAREA;FEATURE_SERIALIZATION;FEATURE_FILEIO;FEATURE_LEGACYCOMPONENTMODEL;FEATURE_CAS_APTCA;FEATURE_SLIMLOCK;FEATURE_MISSINGCONTRACTARGUMENTVALIDATOR;FEATURE_MISSINGREADONLYDICTIONARY;FEATURE_REFLECTIONCONTEXT;FEATURE_CUSTOMREFLECTIONCONTEXT;FEATURE_INTERNAL_REFLECTIONCONTEXT;FEATURE_REFLECTIONONLY;FEATURE_REFLECTIONEMIT;FEATURE_REFLECTIONFILEIO;FEATURE_ADVANCEDREFLECTION;FEATURE_TRACING;FEATURE_OBSERVABLECOLLECTIONS;FEATURE_ADVANCEDCOLLECTIONS;FEATURE_COMINTEROP;FEATURE_APPDOMAINCONTROL;MEF_FEATURE_MVC;MEF_FEATURE_REGISTRATION;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <NoWarn>0414;1570;1572;1573;1591;1699;3021</NoWarn>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\build\ret\</OutputPath>
+ <DefineConstants>TRACE;CLR40;USE_CODEPLEX_KEY;FEATURE_LEGACYSURFACEAREA;FEATURE_SERIALIZATION;FEATURE_FILEIO;FEATURE_LEGACYCOMPONENTMODEL;FEATURE_CAS_APTCA;FEATURE_SLIMLOCK;FEATURE_MISSINGCONTRACTARGUMENTVALIDATOR;FEATURE_MISSINGREADONLYDICTIONARY;FEATURE_REFLECTIONCONTEXT;FEATURE_CUSTOMREFLECTIONCONTEXT;FEATURE_INTERNAL_REFLECTIONCONTEXT;FEATURE_REFLECTIONONLY;FEATURE_REFLECTIONEMIT;FEATURE_REFLECTIONFILEIO;FEATURE_ADVANCEDREFLECTION;FEATURE_TRACING;FEATURE_OBSERVABLECOLLECTIONS;FEATURE_ADVANCEDCOLLECTIONS;FEATURE_COMINTEROP;FEATURE_APPDOMAINCONTROL;MEF_FEATURE_MVC;MEF_FEATURE_REGISTRATION;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <NoWarn>0414;1570;1572;1573;1591;1699;3021</NoWarn>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>CodePlexKey.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="AssemblyInfo.cs" />
+ <Compile Include="Microsoft\Internal\Assumes.cs" />
+ <Compile Include="Microsoft\Internal\AttributeServices.cs" />
+ <Compile Include="Microsoft\Internal\Collections\CollectionServices.cs" />
+ <Compile Include="Microsoft\Internal\Collections\CollectionServices.CollectionOfObject.cs" />
+ <Compile Include="Microsoft\Internal\Collections\EnumerableCardinality.cs" />
+ <Compile Include="Microsoft\Internal\Collections\WeakReferenceCollection.cs" />
+ <Compile Include="Microsoft\Internal\ContractServices.cs" />
+ <Compile Include="Microsoft\Internal\Assumes.InternalErrorException.cs" />
+ <Compile Include="Microsoft\Internal\GenerationServices.cs" />
+ <Compile Include="Microsoft\Internal\LazyServices.cs" />
+ <Compile Include="Microsoft\Internal\Lock.cs" />
+ <Compile Include="Microsoft\Internal\Lock.Reader.cs" />
+ <Compile Include="Microsoft\Internal\Lock.Writer.cs" />
+ <Compile Include="Microsoft\Internal\Requires.cs" />
+ <Compile Include="Microsoft\Internal\Runtime\Serialization\SerializationServices.cs" />
+ <Compile Include="Microsoft\Internal\StringComparers.cs" />
+ <Compile Include="Microsoft\Internal\ReflectionServices.cs" />
+ <Compile Include="Microsoft\Internal\ReflectionInvoke.cs" />
+ <Compile Include="Strings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Strings.resx</DependentUpon>
+ <CustomToolNamespace>Microsoft.Internal</CustomToolNamespace>
+ </Compile>
+ <Compile Include="ContractAdditions.cs" />
+ <Compile Include="SuppressMessages.cs" />
+ <Compile Include="SuppressMessagesBaselined.cs" />
+ <Compile Include="System\ComponentModel\Composition\AttributedModelServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\AttributedModel\AttributedModelDiscovery.cs" />
+ <Compile Include="System\ComponentModel\Composition\AttributedModel\AttributedPartCreationInfo.cs" />
+ <Compile Include="System\ComponentModel\Composition\AttributedModel\AttributedExportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\CatalogReflectionContextAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionExceptionDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Diagnostics\CompositionTrace.cs" />
+ <Compile Include="System\ComponentModel\Composition\Diagnostics\CompositionTraceId.cs" />
+ <Compile Include="System\ComponentModel\Composition\ConstraintServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionContractMismatchException.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionError.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionResultOfT.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.FactoryExport.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.PartCreatorExport.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.ScopeFactoryExport.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.ScopeManager.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionContainer.CompositionServiceShim.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionLock.cs" />
+ <Compile Include="System\ComponentModel\Composition\Diagnostics\CompositionTraceSource.cs" />
+ <Compile Include="System\ComponentModel\Composition\Diagnostics\TraceWriter.cs" />
+ <Compile Include="System\ComponentModel\Composition\Diagnostics\TraceSourceTraceWriter.cs" />
+ <Compile Include="System\ComponentModel\Composition\Diagnostics\SilverlightTraceWriter.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ImportSourceImportDefinitionHelpers.cs" />
+ <Compile Include="System\ComponentModel\Composition\ImportCardinalityMismatchExceptionDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\FilteredCatalog.DependenciesTraversal.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\FilteredCatalog.DependentsTraversal.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\FilteredCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\FilteredCatalog.Traversal.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\FilteredCatalog.IComposablePartCatalogTraversal.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ScopingExtensions.cs" />
+ <Compile Include="System\ComponentModel\Composition\InheritedExportAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportServices.DisposableLazy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\AtomicComposition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\AtomicCompositionExtensions.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionConstants.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionOptions.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.CatalogChangeProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ComposablePartExceptionDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionScopeDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionScopeDefinitionDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\IPartCreatorImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\PrimitivesServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ExportfactoryCreator.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ExportfactoryCreator.LifetimeContext.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\GenericServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\GenericSpecializationPartCreationInfo.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\PartCreatorExportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\PartCreatorParameterImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\PartCreatorMemberImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\IAttributedImport.cs" />
+ <Compile Include="System\ComponentModel\Composition\ImportCardinalityMismatchException.cs" />
+ <Compile Include="System\ComponentModel\Composition\ImportManyAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\ErrorBuilder.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionErrorDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExceptionBuilder.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportCardinalityCheckResult.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportFactoryOfT.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportFactoryOfTTMetadata.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportLifetimeContextOfT.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\AggregateCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\AggregateExportProvider.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\AssemblyCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\AssemblyCatalogDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.CatalogExport.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExportProvider.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CatalogExtensions.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ComposablePartCatalogChangeEventArgs.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ComposablePartCatalogCollection.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ComposablePartExportProvider.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionBatch.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionBatch.SingleExportComposablePart.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionContainer.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionService.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\CompositionServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ExportProvider.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ExportProvider.GetExportOverrides.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ExportsChangeEventArgs.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ImportEngine.RecompositionManager.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ImportEngine.EngineContext.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ImportEngine.PartManager.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ImportEngine.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\INotifyComposablePartCatalogChanged.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\TypeCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\ImportingConstructorAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\IPartImportsSatisfiedNotification.cs" />
+ <Compile Include="System\ComponentModel\Composition\MetadataServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ComposablePart.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ComposablePartCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ComposablePartCatalogDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ComposablePartDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ComposablePartException.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\CompositionElement.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\CompositionElementDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\CompositionElementExtensions.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ContractBasedImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\Export.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ExportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ExportedDelegate.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ICompositionElement.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ImportCardinality.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\ImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\Primitives\SerializableCompositionElement.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\DisposableReflectionComposablePart.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\IReflectionPartCreationInfo.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\LazyMemberInfo.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionItemType.cs" />
+ <Compile Include="System\ComponentModel\Composition\MetadataViewProvider.cs" />
+ <Compile Include="System\ComponentModel\Composition\MetadataViewImplementationAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\PartCreationPolicyAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\PartMetadataAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\PartNotDiscoverableAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionExtensions.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ImportingParameter.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ImportingItem.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ExportingMember.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ImportingMember.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ImportType.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionComposablePart.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionComposablePartDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionMemberExportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionMemberImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionModelServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionParameterImportDefinition.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionWritableMember.cs" />
+ <Compile Include="System\ComponentModel\Composition\MetadataViewGenerator.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionField.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionMember.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionParameter.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionProperty.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionType.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionItem.cs" />
+ <Compile Include="System\ComponentModel\Composition\ReflectionModel\ReflectionMethod.cs" />
+ <Compile Include="System\ComponentModel\Composition\ChangeRejectedException.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionException.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionErrorId.cs" />
+ <Compile Include="System\ComponentModel\Composition\CompositionResult.cs" />
+ <Compile Include="System\ComponentModel\Composition\ContractNameServices.cs" />
+ <Compile Include="System\ComponentModel\Composition\CreationPolicy.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\ExportMetadataAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\ICompositionService.cs" />
+ <Compile Include="System\ComponentModel\Composition\ImportAttribute.cs" />
+ <Compile Include="System\ComponentModel\Composition\ImportSource.cs" />
+ <Compile Include="System\ComponentModel\Composition\MetadataAttributeAttribute.cs" />
+ <Compile Include="System\LazyOfTTMetadata.cs" />
+ <Compile Include="PlatformWorkarounds.cs" />
+ <Compile Include="Microsoft\Internal\Collections\ReadOnlyDictionary.cs" />
+ <Compile Include="Microsoft\Internal\Collections\ReadOnlyDictionaryDebuggerProxy.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\ApplicationCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\DirectoryCatalog.cs" />
+ <Compile Include="System\ComponentModel\Composition\Hosting\DirectoryCatalog.DirectoryCatalogDebuggerProxy.cs" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="VersionInfo.cs" />
+ <None Include="CodePlexKey.snk" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="mscorlib" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\InternalReflectionContext\System.Reflection.Context.csproj">
+ <Project>{0900B66B-65A1-4653-B3FD-C9A7E76297F1}</Project>
+ <Name>System.Reflection.Context.CodePlex</Name>
+ </ProjectReference>
+ </ItemGroup>
+
+ <ItemGroup>
+ <EmbeddedResource Include="Strings.resx">
+ <SubType>Designer</SubType>
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+ <CustomToolNamespace>Microsoft.Internal</CustomToolNamespace>
+ </EmbeddedResource>
+ </ItemGroup>
+
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/ContractAdditions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/ContractAdditions.cs new file mode 100644 index 00000000000..cc3fcddc640 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/ContractAdditions.cs @@ -0,0 +1,113 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Primitives; +using System.Linq; + +namespace System.Diagnostics.Contracts +{ +#if CONTRACTS_FULL + [ContractClassFor(typeof(ComposablePart))] + internal abstract class ComposablePartContract : ComposablePart + { + public override IEnumerable<ExportDefinition> ExportDefinitions + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ExportDefinition>>() != null); + + throw new NotImplementedException(); + } + } + + public override IEnumerable<ImportDefinition> ImportDefinitions + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ImportDefinition>>() != null); + + throw new NotImplementedException(); + } + } + + public override object GetExportedValue(ExportDefinition definition) + { + Contract.Requires(definition != null); + + throw new NotImplementedException(); + } + + public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports) + { + Contract.Requires(definition != null); + Contract.Requires(exports != null); + + throw new NotImplementedException(); + } + } + + [ContractClassFor(typeof(ComposablePartDefinition))] + internal abstract class ComposablePartDefinitionContract : ComposablePartDefinition + { + public override IEnumerable<ExportDefinition> ExportDefinitions + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ExportDefinition>>() != null); + Contract.Ensures(Contract.ForAll(Contract.Result<IEnumerable<ExportDefinition>>(), e => e != null)); + + throw new NotImplementedException(); + } + } + + public override IEnumerable<ImportDefinition> ImportDefinitions + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ImportDefinition>>() != null); + Contract.Ensures(Contract.ForAll(Contract.Result<IEnumerable<ImportDefinition>>(), i => i != null)); + + throw new NotImplementedException(); + } + } + + public override ComposablePart CreatePart() + { + Contract.Ensures(Contract.Result<ComposablePart>() != null); + throw new NotImplementedException(); + } + } + + [ContractClassFor(typeof(ICompositionElement))] + internal abstract class ICompositionElementContract : ICompositionElement + { + public string DisplayName + { + get + { + Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>())); + + throw new NotImplementedException(); + } + } + + public ICompositionElement Origin + { + get { throw new NotImplementedException(); } + } + } + + [ContractClassFor(typeof(ICompositionService))] + internal abstract class ICompositionServiceContract : ICompositionService + { + public void SatisfyImportsOnce(ComposablePart part) + { + Contract.Requires(part != null); + throw new NotImplementedException(); + } + } +#endif +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Assumes.InternalErrorException.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Assumes.InternalErrorException.cs new file mode 100644 index 00000000000..aec196251ca --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Assumes.InternalErrorException.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.Serialization; + +namespace Microsoft.Internal +{ + partial class Assumes + { + // The exception that is thrown when an internal assumption failed. + [Serializable] + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")] + private class InternalErrorException : Exception + { + public InternalErrorException(string message) + : base(string.Format(CultureInfo.CurrentCulture, Strings.InternalExceptionMessage, message)) + { + } + +#if FEATURE_SERIALIZATION + [System.Security.SecuritySafeCritical] + protected InternalErrorException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#endif + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Assumes.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Assumes.cs new file mode 100644 index 00000000000..99f7c643ade --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Assumes.cs @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.Serialization; + +namespace Microsoft.Internal +{ + internal static partial class Assumes + { + [DebuggerStepThrough] + internal static void NotNull<T>(T value) + where T : class + { + IsTrue(value != null); + } + + [DebuggerStepThrough] + internal static void NotNull<T1, T2>(T1 value1, T2 value2) + where T1 : class + where T2 : class + { + NotNull(value1); + NotNull(value2); + } + + [DebuggerStepThrough] + internal static void NotNull<T1, T2, T3>(T1 value1, T2 value2, T3 value3) + where T1 : class + where T2 : class + where T3 : class + { + NotNull(value1); + NotNull(value2); + NotNull(value3); + } + + [DebuggerStepThrough] + internal static void NotNullOrEmpty(string value) + { + NotNull(value); + IsTrue(value.Length > 0); + } + + [DebuggerStepThrough] + internal static void IsTrue(bool condition) + { + if (!condition) + { + throw UncatchableException(null); + } + } + + [DebuggerStepThrough] + internal static void IsTrue(bool condition, [Localizable(false)]string message) + { + if (!condition) + { + throw UncatchableException(message); + } + } + + [DebuggerStepThrough] + internal static T NotReachable<T>() + { + throw UncatchableException("Code path should never be reached!"); + } + + [DebuggerStepThrough] + private static Exception UncatchableException([Localizable(false)]string message) + { + return new InternalErrorException(message); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/AttributeServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/AttributeServices.cs new file mode 100644 index 00000000000..6b9f08b61c8 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/AttributeServices.cs @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Microsoft.Internal +{ + internal static class AttributeServices + { + public static T[] GetAttributes<T>(this ICustomAttributeProvider attributeProvider) where T : class + { + return (T[])attributeProvider.GetCustomAttributes(typeof(T), false); + } + + public static T[] GetAttributes<T>(this ICustomAttributeProvider attributeProvider, bool inherit) where T : class + { + return (T[])attributeProvider.GetCustomAttributes(typeof(T), inherit); + } + + public static T GetFirstAttribute<T>(this ICustomAttributeProvider attributeProvider) where T : class + { + return GetAttributes<T>(attributeProvider).FirstOrDefault(); + } + + public static T GetFirstAttribute<T>(this ICustomAttributeProvider attributeProvider, bool inherit) where T : class + { + return GetAttributes<T>(attributeProvider, inherit).FirstOrDefault(); + } + + public static bool IsAttributeDefined<T>(this ICustomAttributeProvider attributeProvider) where T : class + { + return attributeProvider.IsDefined(typeof(T), false); + } + + public static bool IsAttributeDefined<T>(this ICustomAttributeProvider attributeProvider, bool inherit) where T : class + { + return attributeProvider.IsDefined(typeof(T), inherit); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/CollectionServices.CollectionOfObject.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/CollectionServices.CollectionOfObject.cs new file mode 100644 index 00000000000..4406ea65047 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/CollectionServices.CollectionOfObject.cs @@ -0,0 +1,147 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Microsoft.Internal.Collections +{ + internal static partial class CollectionServices + { + public static ICollection<object> GetCollectionWrapper(Type itemType, object collectionObject) + { + Assumes.NotNull(itemType, collectionObject); + + var underlyingItemType = itemType.UnderlyingSystemType; + + if (underlyingItemType == typeof(object)) + { + return (ICollection<object>)collectionObject; + } + + // Most common .Net collections implement IList as well so for those + // cases we can optimize the wrapping instead of using reflection to create + // a generic type. + if (typeof(IList).IsAssignableFrom(collectionObject.GetType())) + { + return new CollectionOfObjectList((IList)collectionObject); + } + + Type collectionType = typeof(CollectionOfObject<>).MakeGenericType(underlyingItemType); + + return (ICollection<object>)Activator.CreateInstance(collectionType, collectionObject); + } + + private class CollectionOfObjectList : ICollection<object> + { + private readonly IList _list; + + public CollectionOfObjectList(IList list) + { + this._list = list; + } + + public void Add(object item) + { + this._list.Add(item); + } + + public void Clear() + { + this._list.Clear(); + } + + public bool Contains(object item) + { + return Assumes.NotReachable<bool>(); + } + + public void CopyTo(object[] array, int arrayIndex) + { + Assumes.NotReachable<object>(); + } + + public int Count + { + get { return Assumes.NotReachable<int>(); } + } + + public bool IsReadOnly + { + get { return this._list.IsReadOnly; } + } + + public bool Remove(object item) + { + return Assumes.NotReachable<bool>(); + } + + public IEnumerator<object> GetEnumerator() + { + return Assumes.NotReachable<IEnumerator<object>>(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return Assumes.NotReachable<IEnumerator>(); + } + } + + private class CollectionOfObject<T> : ICollection<object> + { + private readonly ICollection<T> _collectionOfT; + + public CollectionOfObject(object collectionOfT) + { + this._collectionOfT = (ICollection<T>)collectionOfT; + } + + public void Add(object item) + { + this._collectionOfT.Add((T) item); + } + + public void Clear() + { + this._collectionOfT.Clear(); + } + + public bool Contains(object item) + { + return Assumes.NotReachable<bool>(); + } + + public void CopyTo(object[] array, int arrayIndex) + { + Assumes.NotReachable<object>(); + } + + public int Count + { + get { return Assumes.NotReachable<int>(); } + } + + public bool IsReadOnly + { + get { return this._collectionOfT.IsReadOnly; } + } + + public bool Remove(object item) + { + return Assumes.NotReachable<bool>(); + } + + public IEnumerator<object> GetEnumerator() + { + return Assumes.NotReachable<IEnumerator<object>>(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return Assumes.NotReachable<IEnumerator>(); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/CollectionServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/CollectionServices.cs new file mode 100644 index 00000000000..f994098ae0f --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/CollectionServices.cs @@ -0,0 +1,270 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; + +namespace Microsoft.Internal.Collections +{ + internal static partial class CollectionServices + { + private static readonly Type StringType = typeof(string); + private static readonly Type IEnumerableType = typeof(IEnumerable); + private static readonly Type IEnumerableOfTType = typeof(IEnumerable<>); + private static readonly Type ICollectionOfTType = typeof(ICollection<>); + + public static bool IsEnumerableOfT(Type type) + { + if (type.IsGenericType) + { + Type genericType = type.GetGenericTypeDefinition().UnderlyingSystemType; + + if (genericType == IEnumerableOfTType) + { + return true; + } + } + return false; + } + + public static Type GetEnumerableElementType(Type type) + { + if (type.UnderlyingSystemType == StringType || !IEnumerableType.IsAssignableFrom(type)) + { + return null; + } + + Type closedType; + if (ReflectionServices.TryGetGenericInterfaceType(type, IEnumerableOfTType, out closedType)) + { + return closedType.GetGenericArguments()[0]; + } + + return null; + } + + public static Type GetCollectionElementType(Type type) + { + Type closedType; + if (ReflectionServices.TryGetGenericInterfaceType(type, ICollectionOfTType, out closedType)) + { + return closedType.GetGenericArguments()[0]; + } + + return null; + } + + public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(this IEnumerable<T> source) + { + Assumes.NotNull(source); + + return new ReadOnlyCollection<T>(source.AsArray()); + } + + public static IEnumerable<T> ConcatAllowingNull<T>(this IEnumerable<T> source, IEnumerable<T> second) + { + if (second == null || !second.FastAny()) + { + return source; + } + + if (source == null || !source.FastAny()) + { + return second; + } + + return source.Concat(second); + } + + public static ICollection<T> ConcatAllowingNull<T>(this ICollection<T> source, ICollection<T> second) + { + if (second == null || (second.Count == 0)) + { + return source; + } + + if (source == null || (source.Count == 0)) + { + return second; + } + + List<T> result = new List<T>(source); + result.AddRange(second); + + return result; + } + + public static List<T> FastAppendToListAllowNulls<T>(this List<T> source, IEnumerable<T> second) + { + if (second == null) + { + return source; + } + + // if there's nothing in the source, return the second + if ((source == null) || (source.Count == 0)) + { + return second.AsList(); + } + + // if the second is List<T>, and contains very few elements there's no need for AddRange + List<T> secondAsList = second as List<T>; + if (secondAsList != null) + { + if (secondAsList.Count == 0) + { + return source; + } + else if (secondAsList.Count == 1) + { + source.Add(secondAsList[0]); + return source; + } + } + + // last resort - nothing is null, need to append + source.AddRange(second); + return source; + + } + + public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) + { + foreach(T t in source) + { + action.Invoke(t); + } + } + + public static EnumerableCardinality GetCardinality<T>(this IEnumerable<T> source) + { + Assumes.NotNull(source); + + // Cast to ICollection instead of ICollection<T> for performance reasons. + ICollection collection = source as ICollection; + if (collection != null) + { + switch (collection.Count) + { + case 0: + return EnumerableCardinality.Zero; + + case 1: + return EnumerableCardinality.One; + + default: + return EnumerableCardinality.TwoOrMore; + } + } + + using (var enumerator = source.GetEnumerator()) + { + if (!enumerator.MoveNext()) + { + return EnumerableCardinality.Zero; + } + + if (!enumerator.MoveNext()) + { + return EnumerableCardinality.One; + } + + return EnumerableCardinality.TwoOrMore; + } + } + + public static bool FastAny<T>(this IEnumerable<T> source) + { + // Enumerable.Any<T> underneath doesn't cast to ICollection, + // like it does with many of the other LINQ methods. + // Below is significantly (4x) when mainly working with ICollection + // sources and a little slower if working with mainly IEnumerable<T> + // sources. + + // Cast to ICollection instead of ICollection<T> for performance reasons. + ICollection collection = source as ICollection; + if (collection != null) + { + return collection.Count > 0; + } + + return source.Any(); + } + + public static Stack<T> Copy<T>(this Stack<T> stack) + { + Assumes.NotNull(stack); + + // Stack<T>.GetEnumerator walks from top to bottom + // of the stack, whereas Stack<T>(IEnumerable<T>) + // pushes to bottom from top, so we need to reverse + // the stack to get them in the right order. + return new Stack<T>(stack.Reverse()); + } + + public static T[] AsArray<T>(this IEnumerable<T> enumerable) + { + T[] array = enumerable as T[]; + + if (array != null) + { + return array; + } + + return enumerable.ToArray(); + } + + public static List<T> AsList<T>(this IEnumerable<T> enumerable) + { + List<T> list = enumerable as List<T>; + + if (list != null) + { + return list; + } + + return enumerable.ToList(); + } + + public static bool IsArrayEqual<T>(this T[] thisArray, T[] thatArray) + { + if (thisArray.Length != thatArray.Length) + { + return false; + } + + for(int i=0; i< thisArray.Length; i++) + { + if (!thisArray[i].Equals( thatArray[i])) + { + return false; + } + } + + return true; + } + + public static bool IsCollectionEqual<T>(this IList<T> thisList, IList<T> thatList) + { + if (thisList.Count != thatList.Count) + { + return false; + } + + for (int i = 0; i < thisList.Count; i++) + { + if (!thisList[i].Equals(thatList[i])) + { + return false; + } + } + + return true; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/EnumerableCardinality.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/EnumerableCardinality.cs new file mode 100644 index 00000000000..b3be71c0f77 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/EnumerableCardinality.cs @@ -0,0 +1,14 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace Microsoft.Internal.Collections +{ + internal enum EnumerableCardinality : int + { + Zero = 0, + One = 1, + TwoOrMore = 2, + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/ReadOnlyDictionary.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/ReadOnlyDictionary.cs new file mode 100644 index 00000000000..03269317f54 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/ReadOnlyDictionary.cs @@ -0,0 +1,106 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Internal; + +// This is using the desktop namespace for ReadOnlyDictionary, the source code is in Microsoft\Internal\Collections to keep it seperate from the main MEF codebase. +namespace System.Collections.ObjectModel +{ + + [DebuggerDisplay("Count = {Count}")] + [DebuggerTypeProxy(typeof(ReadOnlyDictionaryDebuggerProxy<,>))] + internal sealed partial class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> + { + private readonly IDictionary<TKey, TValue> _innerDictionary; + + public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary) + { + this._innerDictionary = dictionary ?? new Dictionary<TKey, TValue>(0); + } + + public int Count + { + get { return this._innerDictionary.Count; } + } + + public bool IsReadOnly + { + get { return true; } + } + + public ICollection<TKey> Keys + { + get { return this._innerDictionary.Keys; } + } + + public TValue this[TKey key] + { + get { return this._innerDictionary[key]; } + set { throw new NotSupportedException(Strings.NotSupportedReadOnlyDictionary); } + } + + public ICollection<TValue> Values + { + get { return this._innerDictionary.Values; } + } + + public bool Contains(KeyValuePair<TKey, TValue> item) + { + return this._innerDictionary.Contains(item); + } + + public bool ContainsKey(TKey key) + { + return this._innerDictionary.ContainsKey(key); + } + + public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) + { + this._innerDictionary.CopyTo(array, arrayIndex); + } + + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { + return this._innerDictionary.GetEnumerator(); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return this._innerDictionary.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this._innerDictionary.GetEnumerator(); + } + + void IDictionary<TKey, TValue>.Add(TKey key, TValue value) + { + throw new NotSupportedException(Strings.NotSupportedReadOnlyDictionary); + } + + void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) + { + throw new NotSupportedException(Strings.NotSupportedReadOnlyDictionary); + } + + void ICollection<KeyValuePair<TKey, TValue>>.Clear() + { + throw new NotSupportedException(Strings.NotSupportedReadOnlyDictionary); + } + + bool IDictionary<TKey, TValue>.Remove(TKey key) + { + throw new NotSupportedException(Strings.NotSupportedReadOnlyDictionary); + } + + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) + { + throw new NotSupportedException(Strings.NotSupportedReadOnlyDictionary); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/ReadOnlyDictionaryDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/ReadOnlyDictionaryDebuggerProxy.cs new file mode 100644 index 00000000000..9dda8f4bc58 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/ReadOnlyDictionaryDebuggerProxy.cs @@ -0,0 +1,34 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Microsoft.Internal; + +namespace System.Collections.ObjectModel +{ + + // NOTE: This type cannot be a nested proxy of ReadOnlyDictionary due to a bug + // in the Visual Studio Debugger which causes it to ignore nested generic proxies. + internal class ReadOnlyDictionaryDebuggerProxy<TKey, TValue> + { + private readonly ReadOnlyDictionary<TKey, TValue> _dictionary; + + public ReadOnlyDictionaryDebuggerProxy(ReadOnlyDictionary<TKey, TValue> dictionary) + { + Requires.NotNull(dictionary, "dictionary"); + + _dictionary = dictionary; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public KeyValuePair<TKey, TValue>[] Items + { + // NOTE: This shouldn't be cached, so that on every query of + // the current value of the underlying dictionary is respected. + get { return this._dictionary.ToArray(); } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/WeakReferenceCollection.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/WeakReferenceCollection.cs new file mode 100644 index 00000000000..fa8faddf3f3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Collections/WeakReferenceCollection.cs @@ -0,0 +1,85 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace Microsoft.Internal.Collections +{ + internal class WeakReferenceCollection<T> where T : class + { + private readonly List<WeakReference> _items = new List<WeakReference>(); + + public void Add(T item) + { + // Only cleanup right before we need to reallocate space. + if (this._items.Capacity == this._items.Count) + { + this.CleanupDeadReferences(); + } + + this._items.Add(new WeakReference(item)); + } + + public void Remove(T item) + { + int index = IndexOf(item); + + if (index != -1) + { + this._items.RemoveAt(index); + } + } + + public bool Contains(T item) + { + return IndexOf(item) >= 0; + } + + public void Clear() + { + this._items.Clear(); + } + + // Should be executed under at least a read lock. + private int IndexOf(T item) + { + int count = this._items.Count; + for (int i = 0; i < count; i++) + { + if (object.ReferenceEquals(this._items[i].Target, item)) + { + return i; + } + } + return -1; + } + + // Should be executed under a write lock + private void CleanupDeadReferences() + { + this._items.RemoveAll(w => !w.IsAlive); + } + + public List<T> AliveItemsToList() + { + List<T> aliveItems = new List<T>(); + + foreach (var weakItem in this._items) + { + T item = weakItem.Target as T; + + if (item != null) + { + aliveItems.Add(item); + } + } + + return aliveItems; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ContractServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ContractServices.cs new file mode 100644 index 00000000000..eeccabe758f --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ContractServices.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading; +using System.ComponentModel.Composition.Primitives; + +namespace Microsoft.Internal +{ + internal static class ContractServices + { + public static bool TryCast(Type contractType, object value, out object result) + { + if (value == null) + { + result = null; + return true; + } + if (contractType.IsInstanceOfType(value)) + { + result = value; + return true; + } + + // We couldn't cast see if a delegate works for us. + if (typeof(Delegate).IsAssignableFrom(contractType)) + { + ExportedDelegate exportedDelegate = value as ExportedDelegate; + if (exportedDelegate != null) + { + result = exportedDelegate.CreateDelegate(contractType.UnderlyingSystemType); + return (result != null); + } + } + + result = null; + return false; + } + } +} + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/GenerationServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/GenerationServices.cs new file mode 100644 index 00000000000..455b7ce27fe --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/GenerationServices.cs @@ -0,0 +1,333 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Reflection; +using System.Reflection.Emit; + +namespace Microsoft.Internal +{ + internal static class GenerationServices + { + // Type.GetTypeFromHandle + private static readonly MethodInfo _typeGetTypeFromHandleMethod = typeof(Type).GetMethod("GetTypeFromHandle"); + + + // typeofs are pretty expensive, so we cache them statically + private static readonly Type TypeType = typeof(System.Type); + private static readonly Type StringType = typeof(System.String); + private static readonly Type CharType = typeof(System.Char); + private static readonly Type BooleanType = typeof(System.Boolean); + private static readonly Type ByteType = typeof(System.Byte); + private static readonly Type SByteType = typeof(System.SByte); + private static readonly Type Int16Type = typeof(System.Int16); + private static readonly Type UInt16Type = typeof(System.UInt16); + private static readonly Type Int32Type = typeof(System.Int32); + private static readonly Type UInt32Type = typeof(System.UInt32); + private static readonly Type Int64Type = typeof(System.Int64); + private static readonly Type UInt64Type = typeof(System.UInt64); + private static readonly Type DoubleType = typeof(System.Double); + private static readonly Type SingleType = typeof(System.Single); + private static readonly Type IEnumerableTypeofT = typeof(System.Collections.Generic.IEnumerable<>); + private static readonly Type IEnumerableType = typeof(System.Collections.IEnumerable); + + private static readonly MethodInfo ExceptionGetData = typeof(Exception).GetProperty("Data").GetGetMethod(); + private static readonly MethodInfo DictionaryAdd = typeof(IDictionary).GetMethod("Add"); + private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes); + + public static ILGenerator CreateGeneratorForPublicConstructor(this TypeBuilder typeBuilder, Type[] ctrArgumentTypes) + { + ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor( + MethodAttributes.Public, + CallingConventions.Standard, + ctrArgumentTypes); + + ILGenerator ctorIL = ctorBuilder.GetILGenerator(); + ctorIL.Emit(OpCodes.Ldarg_0); + ctorIL.Emit(OpCodes.Call, ObjectCtor); + + return ctorIL; + } + + /// Generates the code that loads the supplied value on the stack + /// This is not as simple as it seems, as different instructions need to be generated depending + /// on its type. + /// We support: + /// 1. All primitive types + /// 2. Strings + /// 3. Enums + /// 4. typeofs + /// 5. nulls + /// 6. Enumerables + /// 7. Delegates on static functions or any of the above + /// Everything else cannot be represented as literals + /// <param name="ilGenerator"></param> + /// <param name="item"></param> + /// <param name="key"></param> + /// <param name="value"></param> + /// <returns></returns> + public static void LoadValue(this ILGenerator ilGenerator, object value) + { + Assumes.NotNull(ilGenerator); + + // + // Get nulls out of the way - they are basically typeless, so we just load null + // + if (value == null) + { + ilGenerator.LoadNull(); + return; + } + + // + // Prepare for literal loading - decide whether we should box, and handle enums properly + // + Type valueType = value.GetType(); + object rawValue = value; + if (valueType.IsEnum) + { + // enums are special - we need to load the underlying constant on the stack + rawValue = Convert.ChangeType(value, Enum.GetUnderlyingType(valueType), null); + valueType = rawValue.GetType(); + } + + // + // Generate IL depending on the valueType - this is messier than it should ever be, but sadly necessary + // + if (valueType == GenerationServices.StringType) + { + // we need to check for strings before enumerables, because strings are IEnumerable<char> + ilGenerator.LoadString((string)rawValue); + } + else if (GenerationServices.TypeType.IsAssignableFrom(valueType)) + { + ilGenerator.LoadTypeOf((Type)rawValue); + } + else if (GenerationServices.IEnumerableType.IsAssignableFrom(valueType)) + { + // NOTE : strings and dictionaries are also enumerables, but we have already handled those + ilGenerator.LoadEnumerable((IEnumerable) rawValue); + } + else if ( + (valueType == GenerationServices.CharType) || + (valueType == GenerationServices.BooleanType) || + (valueType == GenerationServices.ByteType) || + (valueType == GenerationServices.SByteType) || + (valueType == GenerationServices.Int16Type) || + (valueType == GenerationServices.UInt16Type) || + (valueType == GenerationServices.Int32Type) + ) + { + // NOTE : Everything that is 32 bit or less uses ldc.i4. We need to pass int32, even if the actual types is shorter - this is IL memory model + // direct casting to (int) won't work, because the value is boxed, thus we need to use Convert. + // Sadly, this will not work for all cases - namely large uint32 - because they can't semantically fit into 32 signed bits + // We have a special case for that next + ilGenerator.LoadInt((int)Convert.ChangeType(rawValue, typeof(int), CultureInfo.InvariantCulture)); + } + else if (valueType == GenerationServices.UInt32Type) + { + // NOTE : This one is a bit tricky. Ldc.I4 takes an Int32 as an argument, although it really treats it as a 32bit number + // That said, some UInt32 values are larger that Int32.MaxValue, so the Convert call above will fail, which is why + // we need to treat this case individually and cast to uint, and then - unchecked - to int. + ilGenerator.LoadInt(unchecked((int)((uint)rawValue))); + } + else if (valueType == GenerationServices.Int64Type) + { + ilGenerator.LoadLong((long)rawValue); + } + else if (valueType == GenerationServices.UInt64Type) + { + // NOTE : This one is a bit tricky. Ldc.I8 takes an Int64 as an argument, although it really treats it as a 64bit number + // That said, some UInt64 values are larger that Int64.MaxValue, so the direct case we use above (or Convert, for that matter)will fail, which is why + // we need to treat this case individually and cast to ulong, and then - unchecked - to long. + ilGenerator.LoadLong(unchecked((long)((ulong)rawValue))); + } + else if (valueType == GenerationServices.SingleType) + { + ilGenerator.LoadFloat((float)rawValue); + } + else if (valueType == GenerationServices.DoubleType) + { + ilGenerator.LoadDouble((double)rawValue); + } + else + { + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, Strings.InvalidMetadataValue, value.GetType().FullName)); + } + } + + /// Generates the code that adds an object to a dictionary stored in a local variable + /// <param name="ilGenerator"></param> + /// <param name="dictionary"></param> + /// <param name="key"></param> + /// <param name="value"></param> + /// <returns></returns> + public static void AddItemToLocalDictionary(this ILGenerator ilGenerator, LocalBuilder dictionary, object key, object value) + { + Assumes.NotNull(ilGenerator); + Assumes.NotNull(dictionary); + Assumes.NotNull(key); + Assumes.NotNull(value); + + ilGenerator.Emit(OpCodes.Ldloc, dictionary); + ilGenerator.LoadValue(key); + ilGenerator.LoadValue(value); + ilGenerator.Emit(OpCodes.Callvirt, DictionaryAdd); + } + + /// Generates the code that adds an object from a local variable to a dictionary also stored in a local + /// <param name="ilGenerator"></param> + /// <param name="dictionary"></param> + /// <param name="key"></param> + /// <param name="value"></param> + /// <returns></returns> + public static void AddLocalToLocalDictionary(this ILGenerator ilGenerator, LocalBuilder dictionary, object key, LocalBuilder value) + { + Assumes.NotNull(ilGenerator); + Assumes.NotNull(dictionary); + Assumes.NotNull(key); + Assumes.NotNull(value); + + ilGenerator.Emit(OpCodes.Ldloc, dictionary); + ilGenerator.LoadValue(key); + ilGenerator.Emit(OpCodes.Ldloc, value); + ilGenerator.Emit(OpCodes.Callvirt, DictionaryAdd); + } + + /// Generates the code to get the type of an object and store it in a local + /// <param name="ilGenerator"></param> + /// <param name="dictionary"></param> + /// <param name="key"></param> + /// <param name="value"></param> + /// <returns></returns> + public static void GetExceptionDataAndStoreInLocal(this ILGenerator ilGenerator, LocalBuilder exception, LocalBuilder dataStore) + { + Assumes.NotNull(ilGenerator); + Assumes.NotNull(exception); + Assumes.NotNull(dataStore); + + ilGenerator.Emit(OpCodes.Ldloc, exception); + ilGenerator.Emit(OpCodes.Callvirt, ExceptionGetData); + ilGenerator.Emit(OpCodes.Stloc, dataStore); + } + + private static void LoadEnumerable(this ILGenerator ilGenerator, IEnumerable enumerable) + { + Assumes.NotNull(ilGenerator); + Assumes.NotNull(enumerable); + + // We load enumerable as an array - this is the most compact and efficient way of representing it + Type elementType = null; + Type closedType = null; + if (ReflectionServices.TryGetGenericInterfaceType(enumerable.GetType(), GenerationServices.IEnumerableTypeofT, out closedType)) + { + elementType = closedType.GetGenericArguments()[0]; + } + else + { + elementType = typeof(object); + } + + // + // elem[] array = new elem[<enumerable.Count()>] + // + Type generatedArrayType = elementType.MakeArrayType(); + LocalBuilder generatedArrayLocal = ilGenerator.DeclareLocal(generatedArrayType); + + ilGenerator.LoadInt(enumerable.Cast<object>().Count()); + ilGenerator.Emit(OpCodes.Newarr, elementType); + ilGenerator.Emit(OpCodes.Stloc, generatedArrayLocal); + + int index = 0; + foreach (object value in enumerable) + { + // + //array[<index>] = value; + // + ilGenerator.Emit(OpCodes.Ldloc, generatedArrayLocal); + ilGenerator.LoadInt(index); + ilGenerator.LoadValue(value); + if (GenerationServices.IsBoxingRequiredForValue(value) && !elementType.IsValueType) + { + ilGenerator.Emit(OpCodes.Box, value.GetType()); + } + ilGenerator.Emit(OpCodes.Stelem, elementType); + index++; + } + + ilGenerator.Emit(OpCodes.Ldloc, generatedArrayLocal); + } + + private static bool IsBoxingRequiredForValue(object value) + { + if (value == null) + { + return false; + } + else + { + return value.GetType().IsValueType; + } + } + + + private static void LoadNull(this ILGenerator ilGenerator) + { + ilGenerator.Emit(OpCodes.Ldnull); + } + + private static void LoadString(this ILGenerator ilGenerator, string s) + { + Assumes.NotNull(ilGenerator); + if (s == null) + { + ilGenerator.LoadNull(); + } + else + { + ilGenerator.Emit(OpCodes.Ldstr, s); + } + } + + + private static void LoadInt(this ILGenerator ilGenerator, int value) + { + Assumes.NotNull(ilGenerator); + ilGenerator.Emit(OpCodes.Ldc_I4, value); + } + + private static void LoadLong(this ILGenerator ilGenerator, long value) + { + Assumes.NotNull(ilGenerator); + ilGenerator.Emit(OpCodes.Ldc_I8, value); + } + + private static void LoadFloat(this ILGenerator ilGenerator, float value) + { + Assumes.NotNull(ilGenerator); + ilGenerator.Emit(OpCodes.Ldc_R4, value); + } + + private static void LoadDouble(this ILGenerator ilGenerator, double value) + { + Assumes.NotNull(ilGenerator); + ilGenerator.Emit(OpCodes.Ldc_R8, value); + } + + private static void LoadTypeOf(this ILGenerator ilGenerator, Type type) + { + Assumes.NotNull(ilGenerator); + //typeofs() translate into ldtoken and Type::GetTypeFromHandle call + ilGenerator.Emit(OpCodes.Ldtoken, type); + ilGenerator.EmitCall(OpCodes.Call, GenerationServices._typeGetTypeFromHandleMethod, null); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/LazyServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/LazyServices.cs new file mode 100644 index 00000000000..ba3f2592561 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/LazyServices.cs @@ -0,0 +1,26 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Globalization; +using System.Threading; + +namespace Microsoft.Internal +{ + internal static class LazyServices + { + public static T GetNotNullValue<T>(this Lazy<T> lazy, string argument) + where T : class + { + Assumes.NotNull(lazy); + T value = lazy.Value; + if (value == null) + { + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, Strings.LazyServices_LazyResolvesToNull, typeof(T), argument)); + } + + return value; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.Reader.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.Reader.cs new file mode 100644 index 00000000000..1f620349a2e --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.Reader.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace Microsoft.Internal +{ + internal struct ReadLock : IDisposable + { + private readonly Lock _lock; + private int _isDisposed; + + public ReadLock(Lock @lock) + { + this._isDisposed = 0; + this._lock = @lock; + this._lock.EnterReadLock(); + } + + public void Dispose() + { + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) + { + this._lock.ExitReadLock(); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.Writer.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.Writer.cs new file mode 100644 index 00000000000..1e8aef0bd44 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.Writer.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace Microsoft.Internal +{ + internal struct WriteLock : IDisposable + { + private readonly Lock _lock; + private int _isDisposed; + + public WriteLock(Lock @lock) + { + this._isDisposed = 0; + this._lock = @lock; + this._lock.EnterWriteLock(); + } + + public void Dispose() + { + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) + { + this._lock.ExitWriteLock(); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.cs new file mode 100644 index 00000000000..82810ac6121 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Lock.cs @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace Microsoft.Internal +{ + internal sealed class Lock : IDisposable + { +#if (FEATURE_SLIMLOCK) + private ReaderWriterLockSlim _thisLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); + private int _isDisposed = 0; + public void EnterReadLock() + { + this._thisLock.EnterReadLock(); + } + + public void EnterWriteLock() + { + this._thisLock.EnterWriteLock(); + } + + public void ExitReadLock() + { + this._thisLock.ExitReadLock(); + } + + public void ExitWriteLock() + { + this._thisLock.ExitWriteLock(); + } + + public void Dispose() + { + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) + { + this._thisLock.Dispose(); + } + } + +#else + // ReaderWriterLockSlim is not yet implemented on SilverLight + // Satisfies our requirements until it is implemented + object _thisLock = new object(); + + public Lock() + { + } + + public void EnterReadLock() + { + Monitor.Enter(this._thisLock); + } + + public void EnterWriteLock() + { + Monitor.Enter(this._thisLock); + } + + public void ExitReadLock() + { + Monitor.Exit(this._thisLock); + } + + public void ExitWriteLock() + { + Monitor.Exit(this._thisLock); + } + + public void Dispose() + { + } +#endif + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ReflectionInvoke.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ReflectionInvoke.cs new file mode 100644 index 00000000000..51d5dc9d9db --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ReflectionInvoke.cs @@ -0,0 +1,119 @@ +using System; +using System.Reflection; +using System.Security; +using System.Security.Permissions; + +namespace Microsoft.Internal +{ + internal static class ReflectionInvoke + { + public static object SafeCreateInstance(this Type type, params object[] arguments) + { + DemandMemberAccessIfNeeded(type); + + return Activator.CreateInstance(type, arguments); + } + + public static object SafeInvoke(this ConstructorInfo constructor, params object[] arguments) + { + DemandMemberAccessIfNeeded(constructor); + + return constructor.Invoke(arguments); + } + + public static object SafeInvoke(this MethodInfo method, object instance, params object[] arguments) + { + DemandMemberAccessIfNeeded(method); + + return method.Invoke(instance, arguments); + } + + public static object SafeGetValue(this FieldInfo field, object instance) + { + DemandMemberAccessIfNeeded(field); + + return field.GetValue(instance); + } + + public static void SafeSetValue(this FieldInfo field, object instance, object value) + { + DemandMemberAccessIfNeeded(field); + + field.SetValue(instance, value); + } + +#if FEATURE_CAS_APTCA + private static readonly ReflectionPermission _memberAccess = new ReflectionPermission(ReflectionPermissionFlag.MemberAccess); + private static readonly ReflectionPermission _restrictedMemberAccess = new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess); + + public static void DemandMemberAccessIfNeeded(MethodInfo method) + { + if (!method.IsVisible()) + { + DemandMemberAccess(method); + } + } + + private static void DemandMemberAccessIfNeeded(FieldInfo field) + { + if (!field.IsVisible()) + { + DemandMemberAccess(field); + } + } + + public static void DemandMemberAccessIfNeeded(Type type) + { + // Consult UnderlyingSystemType this is the type that Activator.CreateInstance creates + if (!type.UnderlyingSystemType.IsVisible) + { + DemandMemberAccess(type); + } + } + + private static void DemandMemberAccessIfNeeded(ConstructorInfo constructor) + { + if (!constructor.IsVisible()) + { + DemandMemberAccess(constructor); + } + } + + [System.Security.SecuritySafeCritical] + private static void DemandMemberAccess(MemberInfo target) + { + try + { + _memberAccess.Demand(); + } + catch (SecurityException) + { // The caller doesn't have member access, but let's see whether they have access to + // members of assemblies with less or equal permissions (this mimics Reflection's behavior) + + DemandRestrictedMemberAccess(target); + } + } + + [System.Security.SecuritySafeCritical] + private static void DemandRestrictedMemberAccess(MemberInfo target) + { + Assembly targetAssembly = target.Assembly(); + + PermissionSet targetGrantSet = UnsafePermissionSet(targetAssembly); + targetGrantSet.AddPermission(_restrictedMemberAccess); + targetGrantSet.Demand(); + } + + [SecuritySafeCritical] // PermissionSet is [SecurityCritical] + private static PermissionSet UnsafePermissionSet(Assembly assembly) + { + return assembly.PermissionSet; + } +#else + public static void DemandMemberAccessIfNeeded(MethodInfo method) { } + private static void DemandMemberAccessIfNeeded(ConstructorInfo constructor) { } + private static void DemandMemberAccessIfNeeded(FieldInfo field) { } + public static void DemandMemberAccessIfNeeded(Type type) { } +#endif //FEATURE_CAS_APTCA + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ReflectionServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ReflectionServices.cs new file mode 100644 index 00000000000..3c0860ec880 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/ReflectionServices.cs @@ -0,0 +1,171 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.ComponentModel.Composition; + +namespace Microsoft.Internal +{ + internal static class ReflectionServices + { + public static Assembly Assembly(this MemberInfo member) + { + Type type = member as Type; + if (type != null) + { + return type.Assembly; + } + + return member.DeclaringType.Assembly; + } + + public static bool IsVisible(this ConstructorInfo constructor) + { + return constructor.DeclaringType.IsVisible && constructor.IsPublic; + } + + public static bool IsVisible(this FieldInfo field) + { + return field.DeclaringType.IsVisible && field.IsPublic; + } + + public static bool IsVisible(this MethodInfo method) + { + if (!method.DeclaringType.IsVisible) + return false; + + if (!method.IsPublic) + return false; + + if (method.IsGenericMethod) + { + // Check type arguments, for example if we're passed 'Activator.CreateInstance<SomeMefInternalType>()' + foreach (Type typeArgument in method.GetGenericArguments()) + { + if (!typeArgument.IsVisible) + return false; + } + } + + return true; + } + + public static string GetDisplayName(Type declaringType, string name) + { + Assumes.NotNull(declaringType); + + return declaringType.GetDisplayName() + "." + name; + } + + public static string GetDisplayName(this MemberInfo member) + { + Assumes.NotNull(member); + + switch (member.MemberType) + { + case MemberTypes.TypeInfo: + case MemberTypes.NestedType: + + return AttributedModelServices.GetTypeIdentity(((Type)member)); + } + + return GetDisplayName(member.DeclaringType, member.Name); + } + + internal static bool TryGetGenericInterfaceType(Type instanceType, Type targetOpenInterfaceType, out Type targetClosedInterfaceType) + { + // The interface must be open + Assumes.IsTrue(targetOpenInterfaceType.IsInterface); + Assumes.IsTrue(targetOpenInterfaceType.IsGenericTypeDefinition); + Assumes.IsTrue(!instanceType.IsGenericTypeDefinition); + + // if instanceType is an interface, we must first check it directly + if (instanceType.IsInterface && + instanceType.IsGenericType && + instanceType.UnderlyingSystemType.GetGenericTypeDefinition() == targetOpenInterfaceType.UnderlyingSystemType) + { + targetClosedInterfaceType = instanceType; + return true; + } + + try + { + // Purposefully not using FullName here because it results in a significantly + // more expensive implementation of GetInterface, this does mean that we're + // takign the chance that there aren't too many types which implement multiple + // interfaces by the same name... + Type targetInterface = instanceType.GetInterface(targetOpenInterfaceType.Name, false); + if (targetInterface != null && + targetInterface.UnderlyingSystemType.GetGenericTypeDefinition() == targetOpenInterfaceType.UnderlyingSystemType) + { + targetClosedInterfaceType = targetInterface; + return true; + } + } + catch (AmbiguousMatchException) + { + // If there are multiple with the same name we should not pick any + } + + targetClosedInterfaceType = null; + return false; + } + + internal static IEnumerable<PropertyInfo> GetAllProperties(this Type type) + { + return type.GetInterfaces().Concat(new Type[] { type }).SelectMany(itf => itf.GetProperties()); + } + + internal static IEnumerable<MethodInfo> GetAllMethods(this Type type) + { + IEnumerable<MethodInfo> declaredMethods = type.GetDeclaredMethods(); + + Type baseType = type.BaseType; + if (baseType.UnderlyingSystemType != typeof(object)) + { + return declaredMethods.Concat(baseType.GetAllMethods()); + } + else + { + return declaredMethods; + } + } + + private static IEnumerable<MethodInfo> GetDeclaredMethods(this Type type) + { + foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) + { + yield return method; + } + } + + + public static IEnumerable<FieldInfo> GetAllFields(this Type type) + { + IEnumerable<FieldInfo> declaredFields = type.GetDeclaredFields(); + + Type baseType = type.BaseType; + if (baseType.UnderlyingSystemType != typeof(object)) + { + return declaredFields.Concat(baseType.GetAllFields()); + } + else + { + return declaredFields; + } + } + + private static IEnumerable<FieldInfo> GetDeclaredFields(this Type type) + { + foreach (FieldInfo m in type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) + { + yield return m; + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Requires.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Requires.cs new file mode 100644 index 00000000000..245f4df7729 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Requires.cs @@ -0,0 +1,105 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Reflection; + +namespace Microsoft.Internal +{ + internal static class Requires + { + [DebuggerStepThrough] + [ContractArgumentValidator] + public static void NotNull<T>(T value, string parameterName) + where T : class + { + if (value == null) + { + throw new ArgumentNullException(parameterName); + } + Contract.EndContractBlock(); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + public static void NotNullOrEmpty(string value, string parameterName) + { + NotNull(value, parameterName); + + if (value.Length == 0) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ArgumentException_EmptyString, parameterName), parameterName); + } + Contract.EndContractBlock(); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + public static void NotNullOrNullElements<T>(IEnumerable<T> values, string parameterName) + where T : class + { + NotNull(values, parameterName); + NotNullElements(values, parameterName); + Contract.EndContractBlock(); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + public static void NullOrNotNullElements<TKey, TValue>(IEnumerable<KeyValuePair<TKey, TValue>> values, string parameterName) + where TKey : class + where TValue : class + { + NotNullElements(values, parameterName); + Contract.EndContractBlock(); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + public static void NullOrNotNullElements<T>(IEnumerable<T> values, string parameterName) + where T : class + { + NotNullElements(values, parameterName); + Contract.EndContractBlock(); + } + + [ContractArgumentValidator] + private static void NotNullElements<T>(IEnumerable<T> values, string parameterName) + where T : class + { + if (values != null && !Contract.ForAll(values, (value) => value != null)) + { + throw ExceptionBuilder.CreateContainsNullElement(parameterName); + } + Contract.EndContractBlock(); + } + + [ContractArgumentValidator] + private static void NotNullElements<TKey, TValue>(IEnumerable<KeyValuePair<TKey, TValue>> values, string parameterName) + where TKey : class + where TValue : class + { + if (values != null && !Contract.ForAll(values, (keyValue) => keyValue.Key != null && keyValue.Value != null)) + { + throw ExceptionBuilder.CreateContainsNullElement(parameterName); + } + Contract.EndContractBlock(); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + public static void IsInMembertypeSet(MemberTypes value, string parameterName, MemberTypes enumFlagSet) + { + if ((value & enumFlagSet) != value || // Ensure the member is in the set + (value & (value - 1)) != 0) // Ensure that there is only one flag in the value (i.e. value is a power of 2). + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ArgumentOutOfRange_InvalidEnumInSet, parameterName, value, enumFlagSet.ToString()), parameterName); + } + Contract.EndContractBlock(); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Runtime/Serialization/SerializationServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Runtime/Serialization/SerializationServices.cs new file mode 100644 index 00000000000..74d1ca783cf --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/Runtime/Serialization/SerializationServices.cs @@ -0,0 +1,20 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Runtime.Serialization; + +namespace Microsoft.Internal.Runtime.Serialization +{ +#if FEATURE_SERIALIZATION + internal static class SerializationServices + { + public static T GetValue<T>(this SerializationInfo info, string name) + { + Assumes.NotNull(info, name); + + return (T)info.GetValue(name, typeof(T)); + } + } +#endif //FEATURE_SERIALIZATION +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/StringComparers.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/StringComparers.cs new file mode 100644 index 00000000000..5cb9747bedb --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Microsoft/Internal/StringComparers.cs @@ -0,0 +1,20 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace Microsoft.Internal +{ + internal static class StringComparers + { + public static StringComparer ContractName + { + get { return StringComparer.Ordinal; } + } + + public static StringComparer MetadataKeyNames + { + get { return StringComparer.Ordinal; } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/PlatformWorkarounds.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/PlatformWorkarounds.cs new file mode 100644 index 00000000000..4f6800aba5d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/PlatformWorkarounds.cs @@ -0,0 +1,45 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +#if !FEATURE_SERIALIZATION +namespace System +{ + [Conditional("NOT_FEATURE_SERIALIZATION")] // Trick so that the attribute is never actually applied + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)] + internal sealed class SerializableAttribute : Attribute + { + } +} +#endif //!FEATURE_SERIALIZATION + +#if !FEATURE_LEGACYCOMPONENTMODEL +namespace System.ComponentModel +{ + [Conditional("NOT_FEATURE_LEGACYCOMPONENTMODEL")] // Trick so that the attribute is never actually applied + internal sealed class LocalizableAttribute : Attribute + { + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "isLocalizable")] + public LocalizableAttribute(bool isLocalizable) + { + } + } +} +#endif //!FEATURE_LEGACYCOMPONENTMODEL + +// This is temporary as contracts should actually be everywhere. Once CORE_CLR adds back this attribute, this will be gone +#if FEATURE_MISSINGCONTRACTARGUMENTVALIDATOR +namespace System.Diagnostics.Contracts +{ + [Conditional("NOT_FEATURE_MISSINGCONTRACTARGUMENTVALIDATOR")] // Trick so that the attribute is never actually applied + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + internal sealed class ContractArgumentValidatorAttribute : Attribute + { + } +} +#endif //FEATURE_MISSINGCONTRACTARGUMENTVALIDATOR diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Strings.Designer.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Strings.Designer.cs new file mode 100644 index 00000000000..39feed44897 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Strings.Designer.cs @@ -0,0 +1,1044 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.16815 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Microsoft.Internal { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Internal.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized string similar to '{0}' is a reflection-only assembly which is not supported.. + /// </summary> + internal static string Argument_AssemblyReflectionOnly { + get { + return ResourceManager.GetString("Argument_AssemblyReflectionOnly", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to '{0}' contains a reflection-only type which is not supported.. + /// </summary> + internal static string Argument_ElementReflectionOnlyType { + get { + return ResourceManager.GetString("Argument_ElementReflectionOnlyType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 'exports' cannot be empty when ImportDefinition.ImportCardinality is ImportCardinality.ExactlyOne.. + /// </summary> + internal static string Argument_ExportsEmpty { + get { + return ResourceManager.GetString("Argument_ExportsEmpty", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 'exports' cannot contain more than one element when ImportDefinition.ImportCardinality is ImportCardinality.ZeroOrOne or ImportCardinality.ExactlyOne.. + /// </summary> + internal static string Argument_ExportsTooMany { + get { + return ResourceManager.GetString("Argument_ExportsTooMany", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to '{0}' cannot contain a null (Nothing in Visual Basic) element.. + /// </summary> + internal static string Argument_NullElement { + get { + return ResourceManager.GetString("Argument_NullElement", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to '{0}' returns a mapped type that is a reflection-only type which is not supported.. + /// </summary> + internal static string Argument_ReflectionContextReturnsReflectionOnlyType { + get { + return ResourceManager.GetString("Argument_ReflectionContextReturnsReflectionOnlyType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to '{0}' cannot be an empty string ("").. + /// </summary> + internal static string ArgumentException_EmptyString { + get { + return ResourceManager.GetString("ArgumentException_EmptyString", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.. + /// </summary> + internal static string ArgumentOutOfRange_InvalidEnum { + get { + return ResourceManager.GetString("ArgumentOutOfRange_InvalidEnum", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The value of argument '{0}' ({1}) is not supported. Allowed values are : '{2}'.. + /// </summary> + internal static string ArgumentOutOfRange_InvalidEnumInSet { + get { + return ResourceManager.GetString("ArgumentOutOfRange_InvalidEnumInSet", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The argument was a value type which is not supported.. + /// </summary> + internal static string ArgumentValueType { + get { + return ResourceManager.GetString("ArgumentValueType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Assembly file {0} is either not found or not a dll or exe file.. + /// </summary> + internal static string AssemblyFileNotFoundOrWrongType { + get { + return ResourceManager.GetString("AssemblyFileNotFoundOrWrongType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The atomicComposition can no longer be changed because the atomicComposition has already been completed.. + /// </summary> + internal static string AtomicComposition_AlreadyCompleted { + get { + return ResourceManager.GetString("AtomicComposition_AlreadyCompleted", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The atomicComposition already contains an inner atomicComposition and cannot contain more than one atomicComposition at a time.. + /// </summary> + internal static string AtomicComposition_AlreadyNested { + get { + return ResourceManager.GetString("AtomicComposition_AlreadyNested", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The atomicComposition contains another inner atomicComposition and cannot be changed until the that inner atomicComposition has been completed.. + /// </summary> + internal static string AtomicComposition_PartOfAnotherAtomicComposition { + get { + return ResourceManager.GetString("AtomicComposition_PartOfAnotherAtomicComposition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to No exports were found that match the constraint: {0}. + /// </summary> + internal static string CardinalityMismatch_NoExports { + get { + return ResourceManager.GetString("CardinalityMismatch_NoExports", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to More than one export was found that matches the constraint: {0}. + /// </summary> + internal static string CardinalityMismatch_TooManyExports { + get { + return ResourceManager.GetString("CardinalityMismatch_TooManyExports", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ScopingPolicyCatalog does not support catalog mutation.. + /// </summary> + internal static string CatalogMutation_Invalid { + get { + return ResourceManager.GetString("CatalogMutation_Invalid", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Unknown Origin. + /// </summary> + internal static string CompositionElement_UnknownOrigin { + get { + return ResourceManager.GetString("CompositionElement_UnknownOrigin", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The composition remains unchanged. The changes were rejected because of the following error(s): {0}. + /// </summary> + internal static string CompositionException_ChangesRejected { + get { + return ResourceManager.GetString("CompositionException_ChangesRejected", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Element: {0}. + /// </summary> + internal static string CompositionException_ElementPrefix { + get { + return ResourceManager.GetString("CompositionException_ElementPrefix", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Resulting in:. + /// </summary> + internal static string CompositionException_ErrorPrefix { + get { + return ResourceManager.GetString("CompositionException_ErrorPrefix", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Unable to create an instance of the Metadata view '{0}' because a constructor could not be selected. Ensure that the type implements a constructor which takes an argument of type IDictionary<string, object>.. + /// </summary> + internal static string CompositionException_MetadataViewInvalidConstructor { + get { + return ResourceManager.GetString("CompositionException_MetadataViewInvalidConstructor", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The composition produced multiple composition errors, with {0:N0} root causes. The root causes are provided below.. + /// </summary> + internal static string CompositionException_MultipleErrorsWithMultiplePaths { + get { + return ResourceManager.GetString("CompositionException_MultipleErrorsWithMultiplePaths", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to {0} {1}. + /// </summary> + internal static string CompositionException_OriginFormat { + get { + return ResourceManager.GetString("CompositionException_OriginFormat", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to --> . + /// </summary> + internal static string CompositionException_OriginSeparator { + get { + return ResourceManager.GetString("CompositionException_OriginSeparator", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ). + /// </summary> + internal static string CompositionException_PathsCountSeparator { + get { + return ResourceManager.GetString("CompositionException_PathsCountSeparator", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Review the CompositionException.Errors property for more detailed information.. + /// </summary> + internal static string CompositionException_ReviewErrorProperty { + get { + return ResourceManager.GetString("CompositionException_ReviewErrorProperty", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The composition produced a single composition error, with {0:N0} root causes. The root causes are provided below.. + /// </summary> + internal static string CompositionException_SingleErrorWithMultiplePaths { + get { + return ResourceManager.GetString("CompositionException_SingleErrorWithMultiplePaths", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The composition produced a single composition error. The root cause is provided below.. + /// </summary> + internal static string CompositionException_SingleErrorWithSinglePath { + get { + return ResourceManager.GetString("CompositionException_SingleErrorWithSinglePath", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The catalog '{0}' could not load assembly '{1}'. {2}. + /// </summary> + internal static string CompositionTrace_Discovery_AssemblyLoadFailed { + get { + return ResourceManager.GetString("CompositionTrace_Discovery_AssemblyLoadFailed", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The ComposablePartDefinition '{0}' was ignored because it contains no exports.. + /// </summary> + internal static string CompositionTrace_Discovery_DefinitionContainsNoExports { + get { + return ResourceManager.GetString("CompositionTrace_Discovery_DefinitionContainsNoExports", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The ComposablePartDefinition '{0}' was ignored because it was marked with PartNotDiscoverableAttribute.. + /// </summary> + internal static string CompositionTrace_Discovery_DefinitionMarkedWithPartNotDiscoverableAttribute { + get { + return ResourceManager.GetString("CompositionTrace_Discovery_DefinitionMarkedWithPartNotDiscoverableAttribute", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The composable part definition '{0}' was ignored because the export '{1}' has different generic parameters than the part type.. + /// </summary> + internal static string CompositionTrace_Discovery_DefinitionMismatchedExportArity { + get { + return ResourceManager.GetString("CompositionTrace_Discovery_DefinitionMismatchedExportArity", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The member or parameter '{0}' is marked with multiple Import and ImportMany attributes. Only the first attribute encountered will be respected.. + /// </summary> + internal static string CompositionTrace_Discovery_MemberMarkedWithMultipleImportAndImportMany { + get { + return ResourceManager.GetString("CompositionTrace_Discovery_MemberMarkedWithMultipleImportAndImportMany", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The ComposablePartDefinition '{0}' has been rejected. {1}. + /// </summary> + internal static string CompositionTrace_Rejection_DefinitionRejected { + get { + return ResourceManager.GetString("CompositionTrace_Rejection_DefinitionRejected", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The ComposablePartDefinition '{0}' that was previously rejected has been resurrected.. + /// </summary> + internal static string CompositionTrace_Rejection_DefinitionResurrected { + get { + return ResourceManager.GetString("CompositionTrace_Rejection_DefinitionResurrected", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot cast the underlying exported value of type '{0}' to type '{1}'.. + /// </summary> + internal static string ContractMismatch_ExportedValueCannotBeCastToT { + get { + return ResourceManager.GetString("ContractMismatch_ExportedValueCannotBeCastToT", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Unable to create an Instance of the Metadata view '{0}' because the exporter exported the metadata for the item '{1}' with the value '{2}' as type '{3}' but the view imports it as type '{4}'.. + /// </summary> + internal static string ContractMismatch_InvalidCastOnMetadataField { + get { + return ResourceManager.GetString("ContractMismatch_InvalidCastOnMetadataField", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The implementation type for the MetadataView '{0} can not be null.. + /// </summary> + internal static string ContractMismatch_MetadataViewImplementationCanNotBeNull { + get { + return ResourceManager.GetString("ContractMismatch_MetadataViewImplementationCanNotBeNull", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Unable to create an Instance of the Metadata view '{0}' because the implementation class : '{0}' does not implement the MetadataView interface '{1}'.. + /// </summary> + internal static string ContractMismatch_MetadataViewImplementationDoesNotImplementViewInterface { + get { + return ResourceManager.GetString("ContractMismatch_MetadataViewImplementationDoesNotImplementViewInterface", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Unable to create an Instance of the Metadata view '{0}' because the exporter exported the metadata for the item '{1}' with a null value and null is not a valid value for type '{2}'.. + /// </summary> + internal static string ContractMismatch_NullReferenceOnMetadataField { + get { + return ResourceManager.GetString("ContractMismatch_NullReferenceOnMetadataField", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Directory '{0}' could not be found.. + /// </summary> + internal static string DirectoryNotFound { + get { + return ResourceManager.GetString("DirectoryNotFound", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Member or Type '{0}' contains multiple metadata entries with the name '{1}'. The metadata entries could be coming from the ExportMetadataAttribute or from a property of a custom metadata attribute. Either remove the duplicate entries or enable the metadata entry with name '{1}' to allow multiple entries via the IsMultiple property on ExportMetadataAttribute or AttributeUsage.AllowMultiple on custom metadata attributes.. + /// </summary> + internal static string Discovery_DuplicateMetadataNameValues { + get { + return ResourceManager.GetString("Discovery_DuplicateMetadataNameValues", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Property '{0}' has type '{1}' which is an invalid metadata type. Metadata can only contain values with a type that is available to be embedded at compile-time into attributes. For more details of what types are valid reference section 17.1.3 in the C# specification.. + /// </summary> + internal static string Discovery_MetadataContainsValueWithInvalidType { + get { + return ResourceManager.GetString("Discovery_MetadataContainsValueWithInvalidType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Member or Type '{0}' contains a metadata entry with the name '{1}', which is a reserved metadata key name. Either remove this metadata entry or change the name associated with the entry.. + /// </summary> + internal static string Discovery_ReservedMetadataNameUsed { + get { + return ResourceManager.GetString("Discovery_ReservedMetadataNameUsed", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to {0} did not originate from the ExportDefinitions property on this ComposablePart or its ComposablePartDefinition.. + /// </summary> + internal static string ExportDefinitionNotOnThisComposablePart { + get { + return ResourceManager.GetString("ExportDefinitionNotOnThisComposablePart", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ExportFactory subclass '{0}' can not have more than two generic parameters.. + /// </summary> + internal static string ExportFactory_TooManyGenericParameters { + get { + return ResourceManager.GetString("ExportFactory_TooManyGenericParameters", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Export is not valid on an Indexer property. The export '{0}' was not retrieved.. + /// </summary> + internal static string ExportNotValidOnIndexers { + get { + return ResourceManager.GetString("ExportNotValidOnIndexers", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to {0} did not originate from the ImportDefinitions property on this ComposablePart or its ComposablePartDefinition.. + /// </summary> + internal static string ImportDefinitionNotOnThisComposablePart { + get { + return ResourceManager.GetString("ImportDefinitionNotOnThisComposablePart", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The composition failed because it did not complete within '{0:N0}' iterations. This is most likely caused by a cycle in the dependency graph of a part which is marked with a non-shared creation policy.. + /// </summary> + internal static string ImportEngine_ComposeTookTooManyIterations { + get { + return ResourceManager.GetString("ImportEngine_ComposeTookTooManyIterations", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The ComposablePart of type '{0}' cannot be recomposed because it is in an invalid state. It can only be recomposed if it has already been fully previewed or composed.. + /// </summary> + internal static string ImportEngine_InvalidStateForRecomposition { + get { + return ResourceManager.GetString("ImportEngine_InvalidStateForRecomposition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot activate part '{0}'.. + /// </summary> + internal static string ImportEngine_PartCannotActivate { + get { + return ResourceManager.GetString("ImportEngine_PartCannotActivate", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot get export '{0}' from part '{1}'.. + /// </summary> + internal static string ImportEngine_PartCannotGetExportedValue { + get { + return ResourceManager.GetString("ImportEngine_PartCannotGetExportedValue", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot set import '{0}' on part '{1}'.. + /// </summary> + internal static string ImportEngine_PartCannotSetImport { + get { + return ResourceManager.GetString("ImportEngine_PartCannotSetImport", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot compose part '{0}' because a cycle exists in the dependencies between the exports being composed. To break this cycle, consider changing some imports from constructor to property injection.. + /// </summary> + internal static string ImportEngine_PartCycle { + get { + return ResourceManager.GetString("ImportEngine_PartCycle", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Change in exports prevented by non-recomposable import '{0}' on part '{1}'.. + /// </summary> + internal static string ImportEngine_PreventedByExistingImport { + get { + return ResourceManager.GetString("ImportEngine_PreventedByExistingImport", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Could not finishing composing object of type '{0}'. The import '{1}' was not satisfied.. + /// </summary> + internal static string ImportNotSetOnPart { + get { + return ResourceManager.GetString("ImportNotSetOnPart", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Import is not valid on an Indexer property. The import '{0}' was not satisfied.. + /// </summary> + internal static string ImportNotValidOnIndexers { + get { + return ResourceManager.GetString("ImportNotValidOnIndexers", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Internal error occurred. Additional information: '{0}'.. + /// </summary> + internal static string InternalExceptionMessage { + get { + return ResourceManager.GetString("InternalExceptionMessage", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 'reflectionContext' must be a type that is assignable from System.Reflection.ReflectionContext.. + /// </summary> + internal static string InvalidArgument_ReflectionContext { + get { + return ResourceManager.GetString("InvalidArgument_ReflectionContext", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Metadata can only contain values with a type that is available to be embedded at compile-time into attributes. For more details of what types are valid reference section 17.1.3 in the C# specification.. + /// </summary> + internal static string InvalidMetadataValue { + get { + return ResourceManager.GetString("InvalidMetadataValue", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The Type '{0}' supplied is not a valid Metadata View.. + /// </summary> + internal static string InvalidMetadataView { + get { + return ResourceManager.GetString("InvalidMetadataView", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 'definition' cannot be set after Activate has been called because ImportDefinition.IsRecomposable is false.. + /// </summary> + internal static string InvalidOperation_DefinitionCannotBeRecomposed { + get { + return ResourceManager.GetString("InvalidOperation_DefinitionCannotBeRecomposed", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to GetExportedValue cannot be called before prerequisite import '{0}' has been set.. + /// </summary> + internal static string InvalidOperation_GetExportedValueBeforePrereqImportSet { + get { + return ResourceManager.GetString("InvalidOperation_GetExportedValueBeforePrereqImportSet", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A call to Compose occurred during a call to Compose on the same CompositionContainer object. Use the IsComposing property on CompositionContainer to ensure a composition is not already in progress before calling Compose.. + /// </summary> + internal static string InvalidOperationReentrantCompose { + get { + return ResourceManager.GetString("InvalidOperationReentrantCompose", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A CreationPolicy of '(0)' can not be applied to an Import that is not an ExportFactory.. + /// </summary> + internal static string InvalidPartCreationPolicyOnImport { + get { + return ResourceManager.GetString("InvalidPartCreationPolicyOnImport", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A CreationPolicy of '{0}' can not be applied to a ComposablePart.. + /// </summary> + internal static string InvalidPartCreationPolicyOnPart { + get { + return ResourceManager.GetString("InvalidPartCreationPolicyOnPart", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The MetadataView '{0}' is invalid because property '{1}' has a property set method.. + /// </summary> + internal static string InvalidSetterOnMetadataField { + get { + return ResourceManager.GetString("InvalidSetterOnMetadataField", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Accessors must not be null (Nothing in Visual Basic).. + /// </summary> + internal static string LazyMemberInfo_AccessorsNull { + get { + return ResourceManager.GetString("LazyMemberInfo_AccessorsNull", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A member of type '{0}' must have exactly a single accessor of type '{0}'. + /// </summary> + internal static string LazyMemberInfo_InvalidAccessorOnSimpleMember { + get { + return ResourceManager.GetString("LazyMemberInfo_InvalidAccessorOnSimpleMember", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to All event accessors must be methods.. + /// </summary> + internal static string LazyMemberinfo_InvalidEventAccessors_AccessorType { + get { + return ResourceManager.GetString("LazyMemberinfo_InvalidEventAccessors_AccessorType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to An event must have exactly three accessors.. + /// </summary> + internal static string LazyMemberInfo_InvalidEventAccessors_Cardinality { + get { + return ResourceManager.GetString("LazyMemberInfo_InvalidEventAccessors_Cardinality", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to All property accessors must be methods.. + /// </summary> + internal static string LazyMemberinfo_InvalidPropertyAccessors_AccessorType { + get { + return ResourceManager.GetString("LazyMemberinfo_InvalidPropertyAccessors_AccessorType", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A property must have exactly two accessors.. + /// </summary> + internal static string LazyMemberInfo_InvalidPropertyAccessors_Cardinality { + get { + return ResourceManager.GetString("LazyMemberInfo_InvalidPropertyAccessors_Cardinality", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A member must have at least one accessor.. + /// </summary> + internal static string LazyMemberInfo_NoAccessors { + get { + return ResourceManager.GetString("LazyMemberInfo_NoAccessors", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The lazily evaluated value of type '{0}' passed to the ReflectionModelServices API as part of the argument '{1}' must not return null (Nothing in Visual Basic).. + /// </summary> + internal static string LazyServices_LazyResolvesToNull { + get { + return ResourceManager.GetString("LazyServices_LazyResolvesToNull", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to This export does not support the metadata item '{0}'.. + /// </summary> + internal static string MetadataItemNotSupported { + get { + return ResourceManager.GetString("MetadataItemNotSupported", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The {0} member must be overridden by a derived class.. + /// </summary> + internal static string NotImplemented_NotOverriddenByDerived { + get { + return ResourceManager.GetString("NotImplemented_NotOverriddenByDerived", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to This CompositionService does not support catalog changes.. + /// </summary> + internal static string NotSupportedCatalogChanges { + get { + return ResourceManager.GetString("NotSupportedCatalogChanges", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Interface '{0}' is not a valid MetadataView; MetadataViews do not support non-public interfaces, and interfaces that contain members that are not properties.. + /// </summary> + internal static string NotSupportedInterfaceMetadataView { + get { + return ResourceManager.GetString("NotSupportedInterfaceMetadataView", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The underlying dictionary is read-only.. + /// </summary> + internal static string NotSupportedReadOnlyDictionary { + get { + return ResourceManager.GetString("NotSupportedReadOnlyDictionary", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to This property cannot be set after the object's public surface has been accessed.. + /// </summary> + internal static string ObjectAlreadyInitialized { + get { + return ResourceManager.GetString("ObjectAlreadyInitialized", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to This object has not been initialized - the property '{0}' must be set.. + /// </summary> + internal static string ObjectMustBeInitialized { + get { + return ResourceManager.GetString("ObjectMustBeInitialized", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Currently composing another batch in this ComposablePartExportProvider. Only one batch can be composed at a time.. + /// </summary> + internal static string ReentrantCompose { + get { + return ResourceManager.GetString("ReentrantCompose", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to A ReflectionContext must have a default constructor.. + /// </summary> + internal static string ReflectionContext_Requires_DefaultConstructor { + get { + return ResourceManager.GetString("ReflectionContext_Requires_DefaultConstructor", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The type specified in the ReflectionContextDiscoveryAttribute must be assignable to System.Reflection.ReflectionContext.. + /// </summary> + internal static string ReflectionContext_Type_Required { + get { + return ResourceManager.GetString("ReflectionContext_Type_Required", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot get the value of property '{0}', because the member is not readable. The property must have an accessible getter.. + /// </summary> + internal static string ReflectionModel_ExportNotReadable { + get { + return ResourceManager.GetString("ReflectionModel_ExportNotReadable", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to An exception occurred while trying to get the value of property '{0}'.. + /// </summary> + internal static string ReflectionModel_ExportThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ExportThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the collection '{0}' because an exception occurred while calling the Add method on the type '{1}'.. + /// </summary> + internal static string ReflectionModel_ImportCollectionAddThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionAddThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the collection '{0}' because an exception occurred while calling the Clear method on the type '{1}'.. + /// </summary> + internal static string ReflectionModel_ImportCollectionClearThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionClearThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the collection '{0}' because an exception occurred while calling the default constructor on the type '{1}'.. + /// </summary> + internal static string ReflectionModel_ImportCollectionConstructionThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionConstructionThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the collection '{0}' because an exception occurred while trying to access the collection value. If the collection is not IEnumerable<T> or T[] it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.. + /// </summary> + internal static string ReflectionModel_ImportCollectionGetThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionGetThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the collection '{0}' because an exception occurred while reading the IsReadOnly property on the type '{1}'.. + /// </summary> + internal static string ReflectionModel_ImportCollectionIsReadOnlyThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionIsReadOnlyThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the collection '{0}' because it does not implement ICollection<T> or is read-only. If the collection is not IEnumerable<T> or T[] it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.. + /// </summary> + internal static string ReflectionModel_ImportCollectionNotWritable { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionNotWritable", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot populate the value of enumerable member '{0}' because it is null (Nothing in Visual Basic). If the collection is not IEnumerable<T> or T[] it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.. + /// </summary> + internal static string ReflectionModel_ImportCollectionNull { + get { + return ResourceManager.GetString("ReflectionModel_ImportCollectionNull", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The importing constructor on type '{0}' is using ImportManyAttribute on parameter '{1}' with a non-assignable type. On constructor parameters the ImportManyAttribute only supports importing into types T[] or IEnumerable<T>.. + /// </summary> + internal static string ReflectionModel_ImportManyOnParameterCanOnlyBeAssigned { + get { + return ResourceManager.GetString("ReflectionModel_ImportManyOnParameterCanOnlyBeAssigned", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to The export '{0}' is not assignable to type '{1}'.. + /// </summary> + internal static string ReflectionModel_ImportNotAssignableFromExport { + get { + return ResourceManager.GetString("ReflectionModel_ImportNotAssignableFromExport", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot set the value of '{0}' because the member is not writable. If the member is a property, it must have an accessible setter; otherwise, if it is a field, it must not be read-only.. + /// </summary> + internal static string ReflectionModel_ImportNotWritable { + get { + return ResourceManager.GetString("ReflectionModel_ImportNotWritable", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to An exception occurred while trying to set the value of property '{0}'.. + /// </summary> + internal static string ReflectionModel_ImportThrewException { + get { + return ResourceManager.GetString("ReflectionModel_ImportThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ExportDefinition of type '{0}' cannot be used in this context. Only export definitions produced by the ReflectionModelServices.CreateExportDefinition are supported.. + /// </summary> + internal static string ReflectionModel_InvalidExportDefinition { + get { + return ResourceManager.GetString("ReflectionModel_InvalidExportDefinition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ImportDefinition of type '{0}' cannot be used in this context. Only import definitions produced by the ReflectionModelServices.CreateImportDefinition are supported.. + /// </summary> + internal static string ReflectionModel_InvalidImportDefinition { + get { + return ResourceManager.GetString("ReflectionModel_InvalidImportDefinition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ImportDefinition of type '{0}' cannot be used in this context. Only import definitions produced by the ReflectionModelServices.CreateImportDefinition based on members are supported. Use ReflectionModelServices.IsImportingParameter to determine whether a given import definition is based on a member or a parameter.. + /// </summary> + internal static string ReflectionModel_InvalidMemberImportDefinition { + get { + return ResourceManager.GetString("ReflectionModel_InvalidMemberImportDefinition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ImportDefinition of type '{0}' cannot be used in this context. Only import definitions produced by the ReflectionModelServices.CreateImportDefinition based on parameters are supported. Use ReflectionModelServices.IsImportingParameter to determine whether a given import definition is based on a member or a parameter.. + /// </summary> + internal static string ReflectionModel_InvalidParameterImportDefinition { + get { + return ResourceManager.GetString("ReflectionModel_InvalidParameterImportDefinition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to ComposablePartDefinition of type '{0}' cannot be used in this context. Only part definitions produced by the ReflectionModelServices.CreatePartDefinition are supported.. + /// </summary> + internal static string ReflectionModel_InvalidPartDefinition { + get { + return ResourceManager.GetString("ReflectionModel_InvalidPartDefinition", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to Cannot create an instance of type '{0}' because a constructor could not be selected for construction. Ensure that the type either has a default constructor, or a single constructor marked with the 'System.ComponentModel.Composition.ImportingConstructorAttribute'.. + /// </summary> + internal static string ReflectionModel_PartConstructorMissing { + get { + return ResourceManager.GetString("ReflectionModel_PartConstructorMissing", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to An exception occurred while trying to create an instance of type '{0}'.. + /// </summary> + internal static string ReflectionModel_PartConstructorThrewException { + get { + return ResourceManager.GetString("ReflectionModel_PartConstructorThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to An exception occurred while calling the 'OnImportsSatisfied' method on type '{0}'.. + /// </summary> + internal static string ReflectionModel_PartOnImportsSatisfiedThrewException { + get { + return ResourceManager.GetString("ReflectionModel_PartOnImportsSatisfiedThrewException", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to {0} (Types='{1}').. + /// </summary> + internal static string TypeCatalog_DisplayNameFormat { + get { + return ResourceManager.GetString("TypeCatalog_DisplayNameFormat", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to <Empty>. + /// </summary> + internal static string TypeCatalog_Empty { + get { + return ResourceManager.GetString("TypeCatalog_Empty", resourceCulture); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Strings.resx b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Strings.resx new file mode 100644 index 00000000000..27fcfcaff3e --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/Strings.resx @@ -0,0 +1,447 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="ArgumentException_EmptyString" xml:space="preserve"> + <value>'{0}' cannot be an empty string ("").</value> + </data> + <data name="ArgumentOutOfRange_InvalidEnum" xml:space="preserve"> + <value>The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.</value> + </data> + <data name="ArgumentValueType" xml:space="preserve"> + <value>The argument was a value type which is not supported.</value> + </data> + <data name="Argument_AssemblyReflectionOnly" xml:space="preserve"> + <value>'{0}' is a reflection-only assembly which is not supported.</value> + </data> + <data name="Argument_NullElement" xml:space="preserve"> + <value>'{0}' cannot contain a null (Nothing in Visual Basic) element.</value> + </data> + <data name="AssemblyFileNotFoundOrWrongType" xml:space="preserve"> + <value>Assembly file {0} is either not found or not a dll or exe file.</value> + </data> + <data name="CardinalityMismatch_NoExports" xml:space="preserve"> + <value>No exports were found that match the constraint: {0}</value> + </data> + <data name="CardinalityMismatch_TooManyExports" xml:space="preserve"> + <value>More than one export was found that matches the constraint: {0}</value> + </data> + <data name="ImportEngine_ComposeTookTooManyIterations" xml:space="preserve"> + <value>The composition failed because it did not complete within '{0:N0}' iterations. This is most likely caused by a cycle in the dependency graph of a part which is marked with a non-shared creation policy.</value> + </data> + <data name="ContractMismatch_ExportedValueCannotBeCastToT" xml:space="preserve"> + <value>Cannot cast the underlying exported value of type '{0}' to type '{1}'.</value> + </data> + <data name="DirectoryNotFound" xml:space="preserve"> + <value>Directory '{0}' could not be found.</value> + </data> + <data name="ReflectionModel_PartConstructorThrewException" xml:space="preserve"> + <value>An exception occurred while trying to create an instance of type '{0}'.</value> + </data> + <data name="ReflectionModel_ExportThrewException" xml:space="preserve"> + <value>An exception occurred while trying to get the value of property '{0}'.</value> + </data> + <data name="ReflectionModel_PartOnImportsSatisfiedThrewException" xml:space="preserve"> + <value>An exception occurred while calling the 'OnImportsSatisfied' method on type '{0}'.</value> + </data> + <data name="ReflectionModel_ImportThrewException" xml:space="preserve"> + <value>An exception occurred while trying to set the value of property '{0}'.</value> + </data> + <data name="ExportDefinitionNotOnThisComposablePart" xml:space="preserve"> + <value>{0} did not originate from the ExportDefinitions property on this ComposablePart or its ComposablePartDefinition.</value> + </data> + <data name="ReflectionModel_ImportCollectionNotWritable" xml:space="preserve"> + <value>Cannot populate the collection '{0}' because it does not implement ICollection<T> or is read-only. If the collection is not IEnumerable<T> or T[] it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.</value> + </data> + <data name="ReflectionModel_ImportCollectionNull" xml:space="preserve"> + <value>Cannot populate the value of enumerable member '{0}' because it is null (Nothing in Visual Basic). If the collection is not IEnumerable<T> or T[] it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.</value> + </data> + <data name="ImportEngine_PartCycle" xml:space="preserve"> + <value>Cannot compose part '{0}' because a cycle exists in the dependencies between the exports being composed. To break this cycle, consider changing some imports from constructor to property injection.</value> + </data> + <data name="ImportDefinitionNotOnThisComposablePart" xml:space="preserve"> + <value>{0} did not originate from the ImportDefinitions property on this ComposablePart or its ComposablePartDefinition.</value> + </data> + <data name="ImportNotSetOnPart" xml:space="preserve"> + <value>Could not finishing composing object of type '{0}'. The import '{1}' was not satisfied.</value> + </data> + <data name="ReflectionModel_ImportNotWritable" xml:space="preserve"> + <value>Cannot set the value of '{0}' because the member is not writable. If the member is a property, it must have an accessible setter; otherwise, if it is a field, it must not be read-only.</value> + </data> + <data name="InternalExceptionMessage" xml:space="preserve"> + <value>Internal error occurred. Additional information: '{0}'.</value> + </data> + <data name="InvalidMetadataView" xml:space="preserve"> + <value>The Type '{0}' supplied is not a valid Metadata View.</value> + </data> + <data name="InvalidOperationReentrantCompose" xml:space="preserve"> + <value>A call to Compose occurred during a call to Compose on the same CompositionContainer object. Use the IsComposing property on CompositionContainer to ensure a composition is not already in progress before calling Compose.</value> + </data> + <data name="MetadataItemNotSupported" xml:space="preserve"> + <value>This export does not support the metadata item '{0}'.</value> + </data> + <data name="NotSupportedInterfaceMetadataView" xml:space="preserve"> + <value>Interface '{0}' is not a valid MetadataView; MetadataViews do not support non-public interfaces, and interfaces that contain members that are not properties.</value> + </data> + <data name="ReflectionModel_PartConstructorMissing" xml:space="preserve"> + <value>Cannot create an instance of type '{0}' because a constructor could not be selected for construction. Ensure that the type either has a default constructor, or a single constructor marked with the 'System.ComponentModel.Composition.ImportingConstructorAttribute'.</value> + </data> + <data name="NotImplemented_NotOverriddenByDerived" xml:space="preserve"> + <value>The {0} member must be overridden by a derived class.</value> + </data> + <data name="NotSupportedReadOnlyDictionary" xml:space="preserve"> + <value>The underlying dictionary is read-only.</value> + </data> + <data name="ObjectAlreadyInitialized" xml:space="preserve"> + <value>This property cannot be set after the object's public surface has been accessed.</value> + </data> + <data name="ObjectMustBeInitialized" xml:space="preserve"> + <value>This object has not been initialized - the property '{0}' must be set.</value> + </data> + <data name="ReflectionModel_ImportNotAssignableFromExport" xml:space="preserve"> + <value>The export '{0}' is not assignable to type '{1}'.</value> + </data> + <data name="ReflectionModel_ExportNotReadable" xml:space="preserve"> + <value>Cannot get the value of property '{0}', because the member is not readable. The property must have an accessible getter.</value> + </data> + <data name="Argument_ElementReflectionOnlyType" xml:space="preserve"> + <value>'{0}' contains a reflection-only type which is not supported.</value> + </data> + <data name="InvalidOperation_DefinitionCannotBeRecomposed" xml:space="preserve"> + <value>'definition' cannot be set after Activate has been called because ImportDefinition.IsRecomposable is false.</value> + </data> + <data name="Argument_ExportsEmpty" xml:space="preserve"> + <value>'exports' cannot be empty when ImportDefinition.ImportCardinality is ImportCardinality.ExactlyOne.</value> + </data> + <data name="Argument_ExportsTooMany" xml:space="preserve"> + <value>'exports' cannot contain more than one element when ImportDefinition.ImportCardinality is ImportCardinality.ZeroOrOne or ImportCardinality.ExactlyOne.</value> + </data> + <data name="CompositionElement_UnknownOrigin" xml:space="preserve"> + <value>Unknown Origin</value> + </data> + <data name="ImportEngine_PartCannotActivate" xml:space="preserve"> + <value>Cannot activate part '{0}'.</value> + </data> + <data name="ImportEngine_PartCannotSetImport" xml:space="preserve"> + <value>Cannot set import '{0}' on part '{1}'.</value> + </data> + <data name="ImportEngine_PartCannotGetExportedValue" xml:space="preserve"> + <value>Cannot get export '{0}' from part '{1}'.</value> + </data> + <data name="TypeCatalog_Empty" xml:space="preserve"> + <value><Empty></value> + </data> + <data name="InvalidOperation_GetExportedValueBeforePrereqImportSet" xml:space="preserve"> + <value>GetExportedValue cannot be called before prerequisite import '{0}' has been set.</value> + </data> + <data name="CompositionException_ErrorPrefix" xml:space="preserve"> + <value>Resulting in:</value> + </data> + <data name="CompositionException_MultipleErrorsWithMultiplePaths" xml:space="preserve"> + <value>The composition produced multiple composition errors, with {0:N0} root causes. The root causes are provided below.</value> + </data> + <data name="CompositionException_ReviewErrorProperty" xml:space="preserve"> + <value>Review the CompositionException.Errors property for more detailed information.</value> + </data> + <data name="CompositionException_SingleErrorWithMultiplePaths" xml:space="preserve"> + <value>The composition produced a single composition error, with {0:N0} root causes. The root causes are provided below.</value> + </data> + <data name="CompositionException_SingleErrorWithSinglePath" xml:space="preserve"> + <value>The composition produced a single composition error. The root cause is provided below.</value> + </data> + <data name="ReflectionModel_ImportCollectionGetThrewException" xml:space="preserve"> + <value>Cannot populate the collection '{0}' because an exception occurred while trying to access the collection value. If the collection is not IEnumerable<T> or T[] it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.</value> + </data> + <data name="ReflectionModel_ImportCollectionAddThrewException" xml:space="preserve"> + <value>Cannot populate the collection '{0}' because an exception occurred while calling the Add method on the type '{1}'.</value> + </data> + <data name="ReflectionModel_ImportCollectionClearThrewException" xml:space="preserve"> + <value>Cannot populate the collection '{0}' because an exception occurred while calling the Clear method on the type '{1}'.</value> + </data> + <data name="ReflectionModel_ImportCollectionIsReadOnlyThrewException" xml:space="preserve"> + <value>Cannot populate the collection '{0}' because an exception occurred while reading the IsReadOnly property on the type '{1}'.</value> + </data> + <data name="ReflectionModel_ImportCollectionConstructionThrewException" xml:space="preserve"> + <value>Cannot populate the collection '{0}' because an exception occurred while calling the default constructor on the type '{1}'.</value> + </data> + <data name="CompositionTrace_Discovery_MemberMarkedWithMultipleImportAndImportMany" xml:space="preserve"> + <value>The member or parameter '{0}' is marked with multiple Import and ImportMany attributes. Only the first attribute encountered will be respected.</value> + </data> + <data name="Discovery_MetadataContainsValueWithInvalidType" xml:space="preserve"> + <value>Property '{0}' has type '{1}' which is an invalid metadata type. Metadata can only contain values with a type that is available to be embedded at compile-time into attributes. For more details of what types are valid reference section 17.1.3 in the C# specification.</value> + </data> + <data name="Discovery_DuplicateMetadataNameValues" xml:space="preserve"> + <value>Member or Type '{0}' contains multiple metadata entries with the name '{1}'. The metadata entries could be coming from the ExportMetadataAttribute or from a property of a custom metadata attribute. Either remove the duplicate entries or enable the metadata entry with name '{1}' to allow multiple entries via the IsMultiple property on ExportMetadataAttribute or AttributeUsage.AllowMultiple on custom metadata attributes.</value> + </data> + <data name="Discovery_ReservedMetadataNameUsed" xml:space="preserve"> + <value>Member or Type '{0}' contains a metadata entry with the name '{1}', which is a reserved metadata key name. Either remove this metadata entry or change the name associated with the entry.</value> + </data> + <data name="ReflectionModel_InvalidExportDefinition" xml:space="preserve"> + <value>ExportDefinition of type '{0}' cannot be used in this context. Only export definitions produced by the ReflectionModelServices.CreateExportDefinition are supported.</value> + </data> + <data name="ImportEngine_PreventedByExistingImport" xml:space="preserve"> + <value>Change in exports prevented by non-recomposable import '{0}' on part '{1}'.</value> + </data> + <data name="ReflectionModel_InvalidImportDefinition" xml:space="preserve"> + <value>ImportDefinition of type '{0}' cannot be used in this context. Only import definitions produced by the ReflectionModelServices.CreateImportDefinition are supported.</value> + </data> + <data name="ReflectionModel_InvalidPartDefinition" xml:space="preserve"> + <value>ComposablePartDefinition of type '{0}' cannot be used in this context. Only part definitions produced by the ReflectionModelServices.CreatePartDefinition are supported.</value> + </data> + <data name="ArgumentOutOfRange_InvalidEnumInSet" xml:space="preserve"> + <value>The value of argument '{0}' ({1}) is not supported. Allowed values are : '{2}'.</value> + </data> + <data name="ReflectionModel_InvalidMemberImportDefinition" xml:space="preserve"> + <value>ImportDefinition of type '{0}' cannot be used in this context. Only import definitions produced by the ReflectionModelServices.CreateImportDefinition based on members are supported. Use ReflectionModelServices.IsImportingParameter to determine whether a given import definition is based on a member or a parameter.</value> + </data> + <data name="ReflectionModel_InvalidParameterImportDefinition" xml:space="preserve"> + <value>ImportDefinition of type '{0}' cannot be used in this context. Only import definitions produced by the ReflectionModelServices.CreateImportDefinition based on parameters are supported. Use ReflectionModelServices.IsImportingParameter to determine whether a given import definition is based on a member or a parameter.</value> + </data> + <data name="LazyMemberInfo_AccessorsNull" xml:space="preserve"> + <value>Accessors must not be null (Nothing in Visual Basic).</value> + </data> + <data name="LazyMemberInfo_InvalidAccessorOnSimpleMember" xml:space="preserve"> + <value>A member of type '{0}' must have exactly a single accessor of type '{0}'</value> + </data> + <data name="LazyMemberinfo_InvalidEventAccessors_AccessorType" xml:space="preserve"> + <value>All event accessors must be methods.</value> + </data> + <data name="LazyMemberInfo_InvalidEventAccessors_Cardinality" xml:space="preserve"> + <value>An event must have exactly three accessors.</value> + </data> + <data name="LazyMemberinfo_InvalidPropertyAccessors_AccessorType" xml:space="preserve"> + <value>All property accessors must be methods.</value> + </data> + <data name="LazyMemberInfo_InvalidPropertyAccessors_Cardinality" xml:space="preserve"> + <value>A property must have exactly two accessors.</value> + </data> + <data name="LazyMemberInfo_NoAccessors" xml:space="preserve"> + <value>A member must have at least one accessor.</value> + </data> + <data name="LazyServices_LazyResolvesToNull" xml:space="preserve"> + <value>The lazily evaluated value of type '{0}' passed to the ReflectionModelServices API as part of the argument '{1}' must not return null (Nothing in Visual Basic).</value> + </data> + <data name="InvalidMetadataValue" xml:space="preserve"> + <value>Metadata can only contain values with a type that is available to be embedded at compile-time into attributes. For more details of what types are valid reference section 17.1.3 in the C# specification.</value> + </data> + <data name="ContractMismatch_InvalidCastOnMetadataField" xml:space="preserve"> + <value>Unable to create an Instance of the Metadata view '{0}' because the exporter exported the metadata for the item '{1}' with the value '{2}' as type '{3}' but the view imports it as type '{4}'.</value> + </data> + <data name="ContractMismatch_NullReferenceOnMetadataField" xml:space="preserve"> + <value>Unable to create an Instance of the Metadata view '{0}' because the exporter exported the metadata for the item '{1}' with a null value and null is not a valid value for type '{2}'.</value> + </data> + <data name="InvalidSetterOnMetadataField" xml:space="preserve"> + <value>The MetadataView '{0}' is invalid because property '{1}' has a property set method.</value> + </data> + <data name="CompositionException_ChangesRejected" xml:space="preserve"> + <value>The composition remains unchanged. The changes were rejected because of the following error(s): {0}</value> + </data> + <data name="ImportEngine_InvalidStateForRecomposition" xml:space="preserve"> + <value>The ComposablePart of type '{0}' cannot be recomposed because it is in an invalid state. It can only be recomposed if it has already been fully previewed or composed.</value> + </data> + <data name="AtomicComposition_AlreadyCompleted" xml:space="preserve"> + <value>The atomicComposition can no longer be changed because the atomicComposition has already been completed.</value> + </data> + <data name="AtomicComposition_PartOfAnotherAtomicComposition" xml:space="preserve"> + <value>The atomicComposition contains another inner atomicComposition and cannot be changed until the that inner atomicComposition has been completed.</value> + </data> + <data name="AtomicComposition_AlreadyNested" xml:space="preserve"> + <value>The atomicComposition already contains an inner atomicComposition and cannot contain more than one atomicComposition at a time.</value> + </data> + <data name="ReentrantCompose" xml:space="preserve"> + <value>Currently composing another batch in this ComposablePartExportProvider. Only one batch can be composed at a time.</value> + </data> + <data name="ReflectionModel_ImportManyOnParameterCanOnlyBeAssigned" xml:space="preserve"> + <value>The importing constructor on type '{0}' is using ImportManyAttribute on parameter '{1}' with a non-assignable type. On constructor parameters the ImportManyAttribute only supports importing into types T[] or IEnumerable<T>.</value> + </data> + <data name="CompositionException_ElementPrefix" xml:space="preserve"> + <value>Element: {0}</value> + </data> + <data name="CompositionException_OriginSeparator" xml:space="preserve"> + <value>--> </value> + </data> + <data name="CompositionTrace_Rejection_DefinitionRejected" xml:space="preserve"> + <value>The ComposablePartDefinition '{0}' has been rejected. {1}</value> + </data> + <data name="CompositionTrace_Rejection_DefinitionResurrected" xml:space="preserve"> + <value>The ComposablePartDefinition '{0}' that was previously rejected has been resurrected.</value> + </data> + <data name="CompositionTrace_Discovery_AssemblyLoadFailed" xml:space="preserve"> + <value>The catalog '{0}' could not load assembly '{1}'. {2}</value> + </data> + <data name="CompositionTrace_Discovery_DefinitionContainsNoExports" xml:space="preserve"> + <value>The ComposablePartDefinition '{0}' was ignored because it contains no exports.</value> + </data> + <data name="CompositionTrace_Discovery_DefinitionMarkedWithPartNotDiscoverableAttribute" xml:space="preserve"> + <value>The ComposablePartDefinition '{0}' was ignored because it was marked with PartNotDiscoverableAttribute.</value> + </data> + <data name="CompositionException_MetadataViewInvalidConstructor" xml:space="preserve"> + <value>Unable to create an instance of the Metadata view '{0}' because a constructor could not be selected. Ensure that the type implements a constructor which takes an argument of type IDictionary<string, object>.</value> + </data> + <data name="CompositionException_PathsCountSeparator" xml:space="preserve"> + <value>)</value> + </data> + <data name="CompositionException_OriginFormat" xml:space="preserve"> + <value> {0} {1}</value> + </data> + <data name="TypeCatalog_DisplayNameFormat" xml:space="preserve"> + <value>{0} (Types='{1}').</value> + </data> + <data name="ImportNotValidOnIndexers" xml:space="preserve"> + <value>Import is not valid on an Indexer property. The import '{0}' was not satisfied.</value> + </data> + <data name="ExportNotValidOnIndexers" xml:space="preserve"> + <value>Export is not valid on an Indexer property. The export '{0}' was not retrieved.</value> + </data> + <data name="ReflectionContext_Requires_DefaultConstructor" xml:space="preserve"> + <value>A ReflectionContext must have a default constructor.</value> + </data> + <data name="ReflectionContext_Type_Required" xml:space="preserve"> + <value>The type specified in the ReflectionContextDiscoveryAttribute must be assignable to System.Reflection.ReflectionContext.</value> + </data> + <data name="CompositionTrace_Discovery_DefinitionMismatchedExportArity" xml:space="preserve"> + <value>The composable part definition '{0}' was ignored because the export '{1}' has different generic parameters than the part type.</value> + </data> + <data name="InvalidArgument_ReflectionContext" xml:space="preserve"> + <value>'reflectionContext' must be a type that is assignable from System.Reflection.ReflectionContext.</value> + </data> + <data name="Argument_ReflectionContextReturnsReflectionOnlyType" xml:space="preserve"> + <value>'{0}' returns a mapped type that is a reflection-only type which is not supported.</value> + </data> + <data name="ContractMismatch_MetadataViewImplementationDoesNotImplementViewInterface" xml:space="preserve"> + <value>Unable to create an Instance of the Metadata view '{0}' because the implementation class : '{0}' does not implement the MetadataView interface '{1}'.</value> + </data> + <data name="ContractMismatch_MetadataViewImplementationCanNotBeNull" xml:space="preserve"> + <value>The implementation type for the MetadataView '{0} can not be null.</value> + </data> + <data name="InvalidPartCreationPolicyOnImport" xml:space="preserve"> + <value>A CreationPolicy of '(0)' can not be applied to an Import that is not an ExportFactory.</value> + </data> + <data name="InvalidPartCreationPolicyOnPart" xml:space="preserve"> + <value>A CreationPolicy of '{0}' can not be applied to a ComposablePart.</value> + </data> + <data name="ExportFactory_TooManyGenericParameters" xml:space="preserve"> + <value>ExportFactory subclass '{0}' can not have more than two generic parameters.</value> + </data> + <data name="CatalogMutation_Invalid" xml:space="preserve"> + <value>ScopingPolicyCatalog does not support catalog mutation.</value> + </data> + <data name="NotSupportedCatalogChanges" xml:space="preserve"> + <value>This CompositionService does not support catalog changes.</value> + </data> +</root>
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/SuppressMessages.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/SuppressMessages.cs new file mode 100644 index 00000000000..4c57e17a2c8 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/SuppressMessages.cs @@ -0,0 +1,10 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.ComponentModel.Composition.ReflectionModel")] +[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System")] +[assembly: SuppressMessage("Microsoft.MSInternal", "CA905:SystemNamespacesRequireApproval", Scope = "namespace", Target = "System.ComponentModel.Composition.ReflectionModel", Justification = "Approved by Framework")] + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/SuppressMessagesBaselined.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/SuppressMessagesBaselined.cs new file mode 100644 index 00000000000..b190f952e56 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/SuppressMessagesBaselined.cs @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; + +// The following are untriaged violations, do not add to this list unless you hit a bug in Code Analysis. Any explicitly +// suppressed violations should either be applied against the member or type itself, or if raised against a namespace, +// resource or assembly, placed in SuppressMessages.cs. + +// Code Analysis Bug: ValidateArgumentsOfPublicMethods should not fire on protected members +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.ComposablePartExportProvider.#GetExportsCore(System.ComponentModel.Composition.Primitives.ImportDefinition,System.ComponentModel.Composition.Hosting.AtomicComposition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.AggregateExportProvider.#GetExportsCore(System.ComponentModel.Composition.Primitives.ImportDefinition,System.ComponentModel.Composition.Hosting.AtomicComposition)")] + +// Code Analysis Bug: ValidateArgumentsOfPublicMethods should not fire on usage of Requires.NotNull +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.AttributedModelServices.#AddExportedValue`1(System.ComponentModel.Composition.Hosting.CompositionBatch,System.String,!!0)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.AttributedModelServices.#AddPart(System.ComponentModel.Composition.Hosting.CompositionBatch,System.Object)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.AttributedModelServices.#ComposeExportedValue`1(System.ComponentModel.Composition.Hosting.CompositionContainer,System.String,!!0)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.AttributedModelServices.#ComposeExportedValue`1(System.ComponentModel.Composition.Hosting.CompositionContainer,!!0)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.AttributedModelServices.#ComposeParts(System.ComponentModel.Composition.Hosting.CompositionContainer,System.Object[])")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.AttributedModelServices.#SatisfyImportsOnce(System.ComponentModel.Composition.ICompositionService,System.Object)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.CatalogExportProvider+CatalogChangeProxy.#GetExports(System.ComponentModel.Composition.Primitives.ImportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.CatalogExportProvider.#SourceProvider")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Primitives.ComposablePartCatalog.#GetExports(System.ComponentModel.Composition.Primitives.ImportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Primitives.ComposablePartException.#GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.ComposablePartExportProvider.#Compose(System.ComponentModel.Composition.Hosting.CompositionBatch)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.CompositionContainer.#ReleaseExports(System.Collections.Generic.IEnumerable`1<System.ComponentModel.Composition.Primitives.Export>)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.CompositionContainer.#ReleaseExports`2(System.Collections.Generic.IEnumerable`1<System.Lazy`2<!!0,!!1>>)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.CompositionContainer.#ReleaseExports`1(System.Collections.Generic.IEnumerable`1<System.Lazy`1<!!0>>)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.CompositionError.#.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.CompositionError.#GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.CompositionException.#GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Primitives.ContractBasedImportDefinition.#IsConstraintSatisfiedBy(System.ComponentModel.Composition.Primitives.ExportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.ExportProvider.#GetExports(System.ComponentModel.Composition.Primitives.ImportDefinition,System.ComponentModel.Composition.Hosting.AtomicComposition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.ExportProvider.#OnExportsChanged(System.ComponentModel.Composition.Hosting.ExportsChangeEventArgs)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.ExportProvider.#OnExportsChanging(System.ComponentModel.Composition.Hosting.ExportsChangeEventArgs)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.ImportEngine.#.ctor(System.ComponentModel.Composition.Hosting.ExportProvider,System.Boolean)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.LazyMemberInfo.#.ctor(System.Reflection.MemberInfo)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices.#GetExportingMember(System.ComponentModel.Composition.Primitives.ExportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices.#GetImportingMember(System.ComponentModel.Composition.Primitives.ImportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices.#GetImportingParameter(System.ComponentModel.Composition.Primitives.ImportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices.#GetPartType(System.ComponentModel.Composition.Primitives.ComposablePartDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices.#IsDisposalRequired(System.ComponentModel.Composition.Primitives.ComposablePartDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.ReflectionModel.ReflectionModelServices.#IsImportingParameter(System.ComponentModel.Composition.Primitives.ImportDefinition)")] +[module: SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "System.ComponentModel.Composition.Hosting.TypeCatalog.#GetExports(System.ComponentModel.Composition.Primitives.ImportDefinition)")] + + +[module: SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Scope = "type", Target = "System.ComponentModel.Composition.ChangeRejectedException")] +[module: SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", Scope = "type", Target = "System.ComponentModel.Composition.CompositionException")] +[module: SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Scope = "type", Target = "System.ComponentModel.Composition.CompositionException")] +[module: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "member", Target = "System.ComponentModel.Composition.MetadataViewGenerator.#GenerateInterfaceViewProxyType(System.Type)")] + + + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedExportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedExportDefinition.cs new file mode 100644 index 00000000000..022fa16c571 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedExportDefinition.cs @@ -0,0 +1,75 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.AttributedModel; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Threading; + +namespace System.ComponentModel.Composition.AttributedModel +{ + internal class AttributedExportDefinition : ExportDefinition + { + private readonly AttributedPartCreationInfo _partCreationInfo; + private readonly MemberInfo _member; + private readonly ExportAttribute _exportAttribute; + private readonly Type _typeIdentityType; + + private IDictionary<string, object> _metadata; + + public AttributedExportDefinition(AttributedPartCreationInfo partCreationInfo, MemberInfo member, ExportAttribute exportAttribute, Type typeIdentityType, string contractName) + : base(contractName, (IDictionary<string, object>)null) + { + Assumes.NotNull(partCreationInfo); + Assumes.NotNull(member); + Assumes.NotNull(exportAttribute); + + this._partCreationInfo = partCreationInfo; + this._member = member; + this._exportAttribute = exportAttribute; + this._typeIdentityType = typeIdentityType; + } + + public override IDictionary<string, object> Metadata + { + get + { + if (this._metadata == null) + { + IDictionary<string, object> metadata; + this._member.TryExportMetadataForMember(out metadata); + + string typeIdentity = this._exportAttribute.IsContractNameSameAsTypeIdentity() ? + this.ContractName : + this._member.GetTypeIdentityFromExport(this._typeIdentityType); + + metadata.Add(CompositionConstants.ExportTypeIdentityMetadataName, typeIdentity); + + var partMetadata = this._partCreationInfo.GetMetadata(); + if (partMetadata != null && partMetadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName)) + { + metadata.Add(CompositionConstants.PartCreationPolicyMetadataName, partMetadata[CompositionConstants.PartCreationPolicyMetadataName]); + } + + if ((this._typeIdentityType != null) && (this._member.MemberType != MemberTypes.Method) && this._typeIdentityType.ContainsGenericParameters) + { + metadata.Add(CompositionConstants.GenericExportParametersOrderMetadataName, GenericServices.GetGenericParametersOrder(this._typeIdentityType)); + } + + this._metadata = metadata; + } + return this._metadata; + } + } + } + +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedModelDiscovery.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedModelDiscovery.cs new file mode 100644 index 00000000000..011ef6b40f4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedModelDiscovery.cs @@ -0,0 +1,194 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Diagnostics; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.AttributedModel +{ + internal static class AttributedModelDiscovery + { + public static ComposablePartDefinition CreatePartDefinitionIfDiscoverable(Type type, ICompositionElement origin) + { + AttributedPartCreationInfo creationInfo = new AttributedPartCreationInfo(type, null, false, origin); + if (!creationInfo.IsPartDiscoverable()) + { + return null; + } + + return new ReflectionComposablePartDefinition(creationInfo); + } + + public static ReflectionComposablePartDefinition CreatePartDefinition(Type type, PartCreationPolicyAttribute partCreationPolicy, bool ignoreConstructorImports, ICompositionElement origin) + { + Assumes.NotNull(type); + + AttributedPartCreationInfo creationInfo = new AttributedPartCreationInfo(type, partCreationPolicy, ignoreConstructorImports, origin); + + return new ReflectionComposablePartDefinition(creationInfo); + } + + public static ReflectionComposablePart CreatePart(object attributedPart) + { + Assumes.NotNull(attributedPart); + + // If given an instance then we want to pass the default composition options because we treat it as a shared part + // TODO: ICompositionElement Give this def an origin indicating that it was added directly to the ComposablePartExportProvider. + + ReflectionComposablePartDefinition definition = AttributedModelDiscovery.CreatePartDefinition(attributedPart.GetType(), PartCreationPolicyAttribute.Shared, true, (ICompositionElement)null); + + return new ReflectionComposablePart(definition, attributedPart); + } + +#if FEATURE_REFLECTIONCONTEXT + public static ReflectionComposablePart CreatePart(object attributedPart, ReflectionContext reflectionContext) + { + Assumes.NotNull(attributedPart); + Assumes.NotNull(reflectionContext); + + // If given an instance then we want to pass the default composition options because we treat it as a shared part + // TODO: ICompositionElement Give this def an origin indicating that it was added directly to the ComposablePartExportProvider. + + var mappedType = reflectionContext.MapType(IntrospectionExtensions.GetTypeInfo(attributedPart.GetType())); + if (mappedType.Assembly.ReflectionOnly) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_ReflectionContextReturnsReflectionOnlyType, "reflectionContext"), "reflectionContext"); + } + + ReflectionComposablePartDefinition definition = AttributedModelDiscovery.CreatePartDefinition(mappedType, PartCreationPolicyAttribute.Shared, true, (ICompositionElement)null); + + return CreatePart(definition, attributedPart); + } +#endif //FEATURE_REFLECTIONCONTEXT + + public static ReflectionComposablePart CreatePart(ComposablePartDefinition partDefinition, object attributedPart) + { + Assumes.NotNull(partDefinition); + Assumes.NotNull(attributedPart); + + return new ReflectionComposablePart((ReflectionComposablePartDefinition)partDefinition, attributedPart); + } + + public static ReflectionParameterImportDefinition CreateParameterImportDefinition(ParameterInfo parameter, ICompositionElement origin) + { + Requires.NotNull(parameter, "parameter"); + + ReflectionParameter reflectionParameter = parameter.ToReflectionParameter(); + IAttributedImport attributedImport = AttributedModelDiscovery.GetAttributedImport(reflectionParameter, parameter); + ImportType importType = new ImportType(reflectionParameter.ReturnType, attributedImport.Cardinality); + + if (importType.IsPartCreator) + { + return new PartCreatorParameterImportDefinition( + new Lazy<ParameterInfo>(() => parameter), + origin, + new ContractBasedImportDefinition( + attributedImport.GetContractNameFromImport(importType), + attributedImport.GetTypeIdentityFromImport(importType), + CompositionServices.GetRequiredMetadata(importType.MetadataViewType), + attributedImport.Cardinality, + false, + true, + (attributedImport.RequiredCreationPolicy != CreationPolicy.NewScope) ? CreationPolicy.NonShared : CreationPolicy.NewScope, + CompositionServices.GetImportMetadata(importType, attributedImport))); + } + else + { + // A Standard import is not allowed to be marked as requiring NewScope at this time. + if(attributedImport.RequiredCreationPolicy == CreationPolicy.NewScope) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.InvalidPartCreationPolicyOnImport, + attributedImport.RequiredCreationPolicy), + origin); + } + return new ReflectionParameterImportDefinition( + new Lazy<ParameterInfo>(() => parameter), + attributedImport.GetContractNameFromImport(importType), + attributedImport.GetTypeIdentityFromImport(importType), + CompositionServices.GetRequiredMetadata(importType.MetadataViewType), + attributedImport.Cardinality, + attributedImport.RequiredCreationPolicy, + CompositionServices.GetImportMetadata(importType, attributedImport), + origin); + } + } + + public static ReflectionMemberImportDefinition CreateMemberImportDefinition(MemberInfo member, ICompositionElement origin) + { + Requires.NotNull(member, "member"); + + ReflectionWritableMember reflectionMember = member.ToReflectionWritableMember(); + IAttributedImport attributedImport = AttributedModelDiscovery.GetAttributedImport(reflectionMember, member); + ImportType importType = new ImportType(reflectionMember.ReturnType, attributedImport.Cardinality); + + if (importType.IsPartCreator) + { + return new PartCreatorMemberImportDefinition( + new LazyMemberInfo(member), + origin, + new ContractBasedImportDefinition( + attributedImport.GetContractNameFromImport(importType), + attributedImport.GetTypeIdentityFromImport(importType), + CompositionServices.GetRequiredMetadata(importType.MetadataViewType), + attributedImport.Cardinality, + attributedImport.AllowRecomposition, + false, + (attributedImport.RequiredCreationPolicy != CreationPolicy.NewScope) ? CreationPolicy.NonShared : CreationPolicy.NewScope, + CompositionServices.GetImportMetadata(importType, attributedImport))); + } + else + { + // A Standard parameter import is not allowed to be marked as requiring NewScope at this time. + if(attributedImport.RequiredCreationPolicy == CreationPolicy.NewScope) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.InvalidPartCreationPolicyOnImport, + attributedImport.RequiredCreationPolicy), + origin); + } + + //Does this Import re-export the value if so, make it a rpe-requisite + bool isPrerequisite = member.GetAttributes<ExportAttribute>().Length > 0; + return new ReflectionMemberImportDefinition( + new LazyMemberInfo(member), + attributedImport.GetContractNameFromImport(importType), + attributedImport.GetTypeIdentityFromImport(importType), + CompositionServices.GetRequiredMetadata(importType.MetadataViewType), + attributedImport.Cardinality, + attributedImport.AllowRecomposition, + isPrerequisite, + attributedImport.RequiredCreationPolicy, + CompositionServices.GetImportMetadata(importType, attributedImport), + origin); + } + } + + private static IAttributedImport GetAttributedImport(ReflectionItem item, ICustomAttributeProvider attributeProvider) + { + IAttributedImport[] imports = attributeProvider.GetAttributes<IAttributedImport>(false); + + // For constructor parameters they may not have an ImportAttribute + if (imports.Length == 0) + { + return new ImportAttribute(); + } + + if (imports.Length > 1) + { + CompositionTrace.MemberMarkedWithMultipleImportAndImportMany(item); + } + + // Regardless of how many imports, always return the first one + return imports[0]; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedPartCreationInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedPartCreationInfo.cs new file mode 100644 index 00000000000..c97dca8c612 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModel/AttributedPartCreationInfo.cs @@ -0,0 +1,511 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Diagnostics; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.AttributedModel +{ + internal class AttributedPartCreationInfo : IReflectionPartCreationInfo + { + private readonly Type _type; + private readonly bool _ignoreConstructorImports = false; + private readonly ICompositionElement _origin; + private PartCreationPolicyAttribute _partCreationPolicy = null; + private ConstructorInfo _constructor; + private IEnumerable<ExportDefinition> _exports; + private IEnumerable<ImportDefinition> _imports; + private HashSet<string> _contractNamesOnNonInterfaces; + + public AttributedPartCreationInfo(Type type, PartCreationPolicyAttribute partCreationPolicy, bool ignoreConstructorImports, ICompositionElement origin) + { + Assumes.NotNull(type); + + this._type = type; + this._ignoreConstructorImports = ignoreConstructorImports; + this._partCreationPolicy = partCreationPolicy; + this._origin = origin; + } + + public Type GetPartType() + { + return this._type; + } + + public Lazy<Type> GetLazyPartType() + { + return new Lazy<Type>(this.GetPartType, LazyThreadSafetyMode.PublicationOnly); + } + + public ConstructorInfo GetConstructor() + { + if (this._constructor == null && !this._ignoreConstructorImports) + { + this._constructor = SelectPartConstructor(this._type); + } + return this._constructor; + } + + public IDictionary<string, object> GetMetadata() + { + return this._type.GetPartMetadataForType(this.CreationPolicy); + } + + public IEnumerable<ExportDefinition> GetExports() + { + DiscoverExportsAndImports(); + return this._exports; + } + + public IEnumerable<ImportDefinition> GetImports() + { + DiscoverExportsAndImports(); + return this._imports; + } + + public bool IsDisposalRequired + { + get + { + return typeof(IDisposable).IsAssignableFrom(this.GetPartType()); + } + } + + public bool IsPartDiscoverable() + { + // The part should not be marked with the "NonDiscoverable" + if (this._type.IsAttributeDefined<PartNotDiscoverableAttribute>()) + { + CompositionTrace.DefinitionMarkedWithPartNotDiscoverableAttribute(this._type); + return false; + } + + // The part should have exports + if (!HasExports()) + { + CompositionTrace.DefinitionContainsNoExports(this._type); + return false; + } + + // If the part is generic, all exports should have the same number of generic parameters + // (otherwise we have no way to specialize the part based on an export) + if (!AllExportsHaveMatchingArity()) + { + // The function has already reported all violations via tracing + return false; + } + + return true; + } + + private bool HasExports() + { + return GetExportMembers(this._type).Any() || + GetInheritedExports(this._type).Any(); + } + + private bool AllExportsHaveMatchingArity() + { + bool isArityMatched = true; + if (this._type.ContainsGenericParameters) + { + int partGenericArity = this._type.GetPureGenericArity(); + + // each member should have the same arity + foreach (MemberInfo member in GetExportMembers(this._type).Concat(GetInheritedExports(this._type))) + { + if (member.MemberType == MemberTypes.Method) + { + // open generics are unsupported on methods + if (((MethodInfo)member).ContainsGenericParameters) + { + isArityMatched = false; + CompositionTrace.DefinitionMismatchedExportArity(this._type, member); + continue; + } + } + + if (member.GetDefaultTypeFromMember().GetPureGenericArity() != partGenericArity) + { + isArityMatched = false; + CompositionTrace.DefinitionMismatchedExportArity(this._type, member); + } + } + } + + return isArityMatched; + } + + + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + ICompositionElement ICompositionElement.Origin + { + get { return this._origin; } + } + + public override string ToString() + { + return GetDisplayName(); + } + + private string GetDisplayName() + { + return this.GetPartType().GetDisplayName(); + } + + private CreationPolicy CreationPolicy + { + get + { + if (this._partCreationPolicy == null) + { + this._partCreationPolicy = this._type.GetFirstAttribute<PartCreationPolicyAttribute>() ?? PartCreationPolicyAttribute.Default; + } + + // A Part is not allowed to be marked as NewScope at this time. + if(this._partCreationPolicy.CreationPolicy == CreationPolicy.NewScope) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.InvalidPartCreationPolicyOnPart, + this._partCreationPolicy.CreationPolicy), + this._origin); + } + + return this._partCreationPolicy.CreationPolicy; + } + } + + private static ConstructorInfo SelectPartConstructor(Type type) + { + Assumes.NotNull(type); + + if (type.IsAbstract) + { + return null; + } + + // Only deal with non-static constructors + BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + + ConstructorInfo[] constructors = type.GetConstructors(flags); + + // Should likely only happen for static or abstract types + if (constructors.Length == 0) + { + return null; + } + + // Optimize single default constructor. + if (constructors.Length == 1 && constructors[0].GetParameters().Length == 0) + { + return constructors[0]; + } + + // Select the marked constructor if there is exactly one marked + ConstructorInfo importingConstructor = null; + ConstructorInfo defaultConstructor = null; + foreach (ConstructorInfo constructor in constructors) + { + // an importing constructor found + if (constructor.IsAttributeDefined<ImportingConstructorAttribute>()) + { + if (importingConstructor != null) + { + // more that one importing constructor - return null ot error out on creation + return null; + } + else + { + importingConstructor = constructor; + } + } + // otherwise if we havent seen the default constructor yet, check if this one is it + else if (defaultConstructor == null) + { + if (constructor.GetParameters().Length == 0) + { + defaultConstructor = constructor; + } + } + } + + return importingConstructor ?? defaultConstructor; + } + + private void DiscoverExportsAndImports() + { + // NOTE : in most cases both of these will be null or not null at the same time + // the only situation when that is not the case is when there was a failure during the previous discovery + // and one of them ended up not being set. In that case we will force the discovery again so that the same exception is thrown. + if ((this._exports != null) && (this._imports != null)) + { + return; + } + + this._exports = GetExportDefinitions(); + this._imports = GetImportDefinitions(); + } + + private IEnumerable<ExportDefinition> GetExportDefinitions() + { + List<ExportDefinition> exports = new List<ExportDefinition>(); + + this._contractNamesOnNonInterfaces = new HashSet<string>(); + + // GetExportMembers should only contain the type itself along with the members declared on it, + // it should not contain any base types, members on base types or interfaces on the type. + foreach (MemberInfo member in GetExportMembers(this._type)) + { + foreach (ExportAttribute exportAttribute in member.GetAttributes<ExportAttribute>()) + { + var attributedExportDefinition = this.CreateExportDefinition(member, exportAttribute); + + if (exportAttribute.GetType() == CompositionServices.InheritedExportAttributeType) + { + // Any InheritedExports on the type itself are contributed during this pass + // and we need to do the book keeping for those. + if (!this._contractNamesOnNonInterfaces.Contains(attributedExportDefinition.ContractName)) + { + exports.Add(new ReflectionMemberExportDefinition(member.ToLazyMember(), attributedExportDefinition, this)); + this._contractNamesOnNonInterfaces.Add(attributedExportDefinition.ContractName); + } + } + else + { + exports.Add(new ReflectionMemberExportDefinition(member.ToLazyMember(), attributedExportDefinition, this)); + } + } + } + + // GetInheritedExports should only contain InheritedExports on base types or interfaces. + // The order of types returned here is important because it is used as a + // priority list of which InhertedExport to choose if multiple exists with + // the same contract name. Therefore ensure that we always return the types + // in the hiearchy from most derived to the lowest base type, followed + // by all the interfaces that this type implements. + foreach (Type type in GetInheritedExports(this._type)) + { + foreach (InheritedExportAttribute exportAttribute in type.GetAttributes<InheritedExportAttribute>()) + { + var attributedExportDefinition = this.CreateExportDefinition(type, exportAttribute); + + if (!this._contractNamesOnNonInterfaces.Contains(attributedExportDefinition.ContractName)) + { + exports.Add(new ReflectionMemberExportDefinition(type.ToLazyMember(), attributedExportDefinition, this)); + + if (!type.IsInterface) + { + this._contractNamesOnNonInterfaces.Add(attributedExportDefinition.ContractName); + } + } + } + } + + this._contractNamesOnNonInterfaces = null; // No need to hold this state around any longer + + return exports; + } + + private AttributedExportDefinition CreateExportDefinition(MemberInfo member, ExportAttribute exportAttribute) + { + string contractName = null; + Type typeIdentityType = null; + member.GetContractInfoFromExport(exportAttribute, out typeIdentityType, out contractName); + + return new AttributedExportDefinition(this, member, exportAttribute, typeIdentityType, contractName); + } + + private IEnumerable<MemberInfo> GetExportMembers(Type type) + { + BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + + // If the type is abstract only find local static exports + if (type.IsAbstract) + { + flags &= ~BindingFlags.Instance; + } + else if (IsExport(type)) + { + yield return type; + } + + // Walk the fields + foreach (var member in type.GetFields(flags)) + { + if (IsExport(member)) + { + yield return member; + } + } + + // Walk the properties + foreach (var member in type.GetProperties(flags)) + { + if (IsExport(member)) + { + yield return member; + } + } + + // Walk the methods + foreach (var member in type.GetMethods(flags)) + { + if (IsExport(member)) + { + yield return member; + } + } + } + + private IEnumerable<Type> GetInheritedExports(Type type) + { + // If the type is abstract we aren't interested in type level exports + if (type.IsAbstract) + { + yield break; + } + + // The order of types returned here is important because it is used as a + // priority list of which InhertedExport to choose if multiple exists with + // the same contract name. Therefore ensure that we always return the types + // in the hiearchy from most derived to the lowest base type, followed + // by all the interfaces that this type implements. + + Type currentType = type.BaseType; + + if (currentType == null) + { + yield break; + } + + // Stopping at object instead of null to help with performance. It is a noticable performance + // gain (~5%) if we don't have to try and pull the attributes we know don't exist on object. + // We also need the null check in case we're passed a type that doesn't live in the runtime context. + while (currentType != null && currentType.UnderlyingSystemType != CompositionServices.ObjectType) + { + if (IsInheritedExport(currentType)) + { + yield return currentType; + } + currentType = currentType.BaseType; + } + + foreach (Type iface in type.GetInterfaces()) + { + if (IsInheritedExport(iface)) + { + yield return iface; + } + } + } + + private static bool IsExport(ICustomAttributeProvider attributeProvider) + { + return attributeProvider.IsAttributeDefined<ExportAttribute>(false); + } + + private static bool IsInheritedExport(ICustomAttributeProvider attributedProvider) + { + return attributedProvider.IsAttributeDefined<InheritedExportAttribute>(false); + } + + private IEnumerable<ImportDefinition> GetImportDefinitions() + { + List<ImportDefinition> imports = new List<ImportDefinition>(); + + foreach (MemberInfo member in GetImportMembers(this._type)) + { + ReflectionMemberImportDefinition importDefinition = AttributedModelDiscovery.CreateMemberImportDefinition(member, this); + imports.Add(importDefinition); + } + + var constructor = this.GetConstructor(); + + if (constructor != null) + { + foreach (ParameterInfo parameter in constructor.GetParameters()) + { + ReflectionParameterImportDefinition importDefinition = AttributedModelDiscovery.CreateParameterImportDefinition(parameter, this); + imports.Add(importDefinition); + } + } + + return imports; + } + + private IEnumerable<MemberInfo> GetImportMembers(Type type) + { + if (type.IsAbstract) + { + yield break; + } + + foreach (MemberInfo member in GetDeclaredOnlyImportMembers(type)) + { + yield return member; + } + + // Walk up the type chain until you hit object. + if (type.BaseType != null) + { + Type baseType = type.BaseType; + + // Stopping at object instead of null to help with performance. It is a noticable performance + // gain (~5%) if we don't have to try and pull the attributes we know don't exist on object. + // We also need the null check in case we're passed a type that doesn't live in the runtime context. + while (baseType != null && baseType.UnderlyingSystemType != CompositionServices.ObjectType) + { + foreach (MemberInfo member in GetDeclaredOnlyImportMembers(baseType)) + { + yield return member; + } + baseType = baseType.BaseType; + } + } + } + + private IEnumerable<MemberInfo> GetDeclaredOnlyImportMembers(Type type) + { + BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + + // Walk the fields + foreach (var member in type.GetFields(flags)) + { + if (IsImport(member)) + { + yield return member; + } + } + + // Walk the properties + foreach (var member in type.GetProperties(flags)) + { + if (IsImport(member)) + { + yield return member; + } + } + } + + private static bool IsImport(ICustomAttributeProvider attributeProvider) + { + return attributeProvider.IsAttributeDefined<IAttributedImport>(false); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModelServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModelServices.cs new file mode 100644 index 00000000000..86cea512726 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/AttributedModelServices.cs @@ -0,0 +1,330 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.AttributedModel; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + public static class AttributedModelServices + { + [SuppressMessage("Microsoft.Design", "CA1004")] + public static TMetadataView GetMetadataView<TMetadataView>(IDictionary<string, object> metadata) + { + Requires.NotNull(metadata, "metadata"); + Contract.Ensures(Contract.Result<TMetadataView>() != null); + + return MetadataViewProvider.GetMetadataView<TMetadataView>(metadata); + } + + public static ComposablePart CreatePart(object attributedPart) + { + Requires.NotNull(attributedPart, "attributedPart"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + return AttributedModelDiscovery.CreatePart(attributedPart); + } + +#if FEATURE_REFLECTIONCONTEXT + public static ComposablePart CreatePart(object attributedPart, ReflectionContext reflectionContext) + { + Requires.NotNull(attributedPart, "attributedPart"); + Requires.NotNull(reflectionContext, "reflectionContext"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + return AttributedModelDiscovery.CreatePart(attributedPart, reflectionContext); + } +#endif //FEATURE_REFLECTIONCONTEXT + + public static ComposablePart CreatePart(ComposablePartDefinition partDefinition, object attributedPart) + { + Requires.NotNull(partDefinition, "partDefinition"); + Requires.NotNull(attributedPart, "attributedPart"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + var reflectionComposablePartDefinition = partDefinition as ReflectionComposablePartDefinition; + if(reflectionComposablePartDefinition == null) + { + throw ExceptionBuilder.CreateReflectionModelInvalidPartDefinition("partDefinition", partDefinition.GetType()); + } + + return AttributedModelDiscovery.CreatePart(reflectionComposablePartDefinition, attributedPart); + } + + public static ComposablePartDefinition CreatePartDefinition(Type type, ICompositionElement origin) + { + Requires.NotNull(type, "type"); + Contract.Ensures(Contract.Result<ComposablePartDefinition>() != null); + + return AttributedModelServices.CreatePartDefinition(type, origin, false); + } + + public static ComposablePartDefinition CreatePartDefinition(Type type, ICompositionElement origin, bool ensureIsDiscoverable) + { + Requires.NotNull(type, "type"); + if (ensureIsDiscoverable) + { + return AttributedModelDiscovery.CreatePartDefinitionIfDiscoverable(type, origin); + } + else + { + return AttributedModelDiscovery.CreatePartDefinition(type, null, false, origin); + } + } + + public static string GetTypeIdentity(Type type) + { + Requires.NotNull(type, "type"); + Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>())); + + return ContractNameServices.GetTypeIdentity(type); + } + + public static string GetTypeIdentity(MethodInfo method) + { + Requires.NotNull(method, "method"); + Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>())); + + return ContractNameServices.GetTypeIdentityFromMethod(method); + } + + public static string GetContractName(Type type) + { + Requires.NotNull(type, "type"); + Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>())); + + return AttributedModelServices.GetTypeIdentity(type); + } + + public static ComposablePart AddExportedValue<T>(this CompositionBatch batch, T exportedValue) + { + Requires.NotNull(batch, "batch"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + string contractName = AttributedModelServices.GetContractName(typeof(T)); + + return batch.AddExportedValue<T>(contractName, exportedValue); + } + + public static void ComposeExportedValue<T>(this CompositionContainer container, T exportedValue) + { + Requires.NotNull(container, "container"); + + CompositionBatch batch = new CompositionBatch(); + batch.AddExportedValue<T>(exportedValue); + container.Compose(batch); + } + + public static ComposablePart AddExportedValue<T>(this CompositionBatch batch, string contractName, T exportedValue) + { + Requires.NotNull(batch, "batch"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + string typeIdentity = AttributedModelServices.GetTypeIdentity(typeof(T)); + + IDictionary<string, object> metadata = new Dictionary<string, object>(); + metadata.Add(CompositionConstants.ExportTypeIdentityMetadataName, typeIdentity); + + return batch.AddExport(new Export(contractName, metadata, () => exportedValue)); + } + + public static void ComposeExportedValue<T>(this CompositionContainer container, string contractName, T exportedValue) + { + Requires.NotNull(container, "container"); + + CompositionBatch batch = new CompositionBatch(); + batch.AddExportedValue<T>(contractName, exportedValue); + container.Compose(batch); + } + + public static ComposablePart AddPart(this CompositionBatch batch, object attributedPart) + { + Requires.NotNull(batch, "batch"); + Requires.NotNull(attributedPart, "attributedPart"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + ComposablePart part = AttributedModelServices.CreatePart(attributedPart); + + batch.AddPart(part); + + return part; + } + + public static void ComposeParts(this CompositionContainer container, params object[] attributedParts) + { + Requires.NotNull(container, "container"); + Requires.NotNullOrNullElements(attributedParts, "attributedParts"); + + CompositionBatch batch = new CompositionBatch( + attributedParts.Select(attributedPart => AttributedModelServices.CreatePart(attributedPart)).ToArray(), + Enumerable.Empty<ComposablePart>()); + + container.Compose(batch); + } + + /// <summary> + /// Satisfies the imports of the specified attributed object exactly once and they will not + /// ever be recomposed. + /// </summary> + /// <param name="part"> + /// The attributed object to set the imports. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="compositionService"/> or <paramref name="attributedPart"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ICompositionService"/> has been disposed of. + /// </exception> + public static ComposablePart SatisfyImportsOnce(this ICompositionService compositionService, object attributedPart) + { + Requires.NotNull(compositionService, "compositionService"); + Requires.NotNull(attributedPart, "attributedPart"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + ComposablePart part = AttributedModelServices.CreatePart(attributedPart); + compositionService.SatisfyImportsOnce(part); + + return part; + } + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Satisfies the imports of the specified attributed object exactly once and they will not + /// ever be recomposed. + /// </summary> + /// <param name="part"> + /// The attributed object to set the imports. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="compositionService"/> or <paramref name="attributedPart"/> or <paramref name="reflectionContext"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ICompositionService"/> has been disposed of. + /// </exception> + public static ComposablePart SatisfyImportsOnce(this ICompositionService compositionService, object attributedPart, ReflectionContext reflectionContext) + { + Requires.NotNull(compositionService, "compositionService"); + Requires.NotNull(attributedPart, "attributedPart"); + Requires.NotNull(reflectionContext, "reflectionContext"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + ComposablePart part = AttributedModelServices.CreatePart(attributedPart, reflectionContext); + compositionService.SatisfyImportsOnce(part); + + return part; + } +#endif //FEATURE_REFLECTIONCONTEXT + + /// <summary> + /// Determines whether the specified part exports the specified contract. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="contractType">Type of the contract.</param> + /// <returns> + /// <c>true</c> if the specified part exports the specified contract; otherwise, <c>false</c>. + /// </returns> + public static bool Exports(this ComposablePartDefinition part, Type contractType) + { + Requires.NotNull(part, "part"); + Requires.NotNull(contractType, "contractType"); + + return part.Exports(AttributedModelServices.GetContractName(contractType)); + } + + /// <summary> + /// Determines whether the specified part exports the specified contract. + /// </summary> + /// <typeparam name="T">Type of the contract.</typeparam> + /// <param name="part">The part.</param> + /// <returns> + /// <c>true</c> if the specified part exports the specified contract; otherwise, <c>false</c>. + /// </returns> + public static bool Exports<T>(this ComposablePartDefinition part) + { + Requires.NotNull(part, "part"); + + return part.Exports(typeof(T)); + } + + /// <summary> + /// Determines whether the specified part imports the specified contract. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="contractType">Type of the contract.</param> + /// <returns> + /// <c>true</c> if the specified part imports the specified contract; otherwise, <c>false</c>. + /// </returns> + public static bool Imports(this ComposablePartDefinition part, Type contractType) + { + Requires.NotNull(part, "part"); + Requires.NotNull(contractType, "contractType"); + + return part.Imports(AttributedModelServices.GetContractName(contractType)); + } + + /// <summary> + /// Determines whether the specified part imports the specified contract. + /// </summary> + /// <param name="part">The part.</param> + /// <typeparam name="T">Type of the contract.</typeparam> + /// <returns> + /// <c>true</c> if the specified part imports the specified contract; otherwise, <c>false</c>. + /// </returns> + public static bool Imports<T>(this ComposablePartDefinition part) + { + Requires.NotNull(part, "part"); + + return part.Imports(typeof(T)); + } + + /// <summary> + /// Determines whether the specified part imports the specified contract with the given cardinality. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="contractType">Type of the contract.</param> + /// <param name="importCardinality">The import cardinality.</param> + /// <returns> + /// <c>true</c> if the specified part imports the specified contract with the given cardinality; otherwise, <c>false</c>. + /// </returns> + public static bool Imports(this ComposablePartDefinition part, Type contractType, ImportCardinality importCardinality) + { + Requires.NotNull(part, "part"); + Requires.NotNull(contractType, "contractType"); + + return part.Imports(AttributedModelServices.GetContractName(contractType), importCardinality); + } + + /// <summary> + /// Determines whether the specified part imports the specified contract with the given cardinality. + /// </summary> + /// <param name="part">The part.</param> + /// <typeparam name="T">Type of the contract.</typeparam> + /// <param name="importCardinality">The import cardinality.</param> + /// <returns> + /// <c>true</c> if the specified part imports the specified contract with the given cardinality; otherwise, <c>false</c>. + /// </returns> + public static bool Imports<T>(this ComposablePartDefinition part, ImportCardinality importCardinality) + { + Requires.NotNull(part, "part"); + + return part.Imports(typeof(T), importCardinality); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CatalogReflectionContextAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CatalogReflectionContextAttribute.cs new file mode 100644 index 00000000000..1a5dfad029b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CatalogReflectionContextAttribute.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- + +#if FEATURE_REFLECTIONCONTEXT + +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Enables the AssemblyCatalog to discover user provided ReflectionContexts. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes")] + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false,Inherited = true)] + public class CatalogReflectionContextAttribute : Attribute + { + Type _reflectionContextType; + + public CatalogReflectionContextAttribute(Type reflectionContextType) + { + Requires.NotNull(reflectionContextType, "reflectionContextType"); + + this._reflectionContextType = reflectionContextType; + } + + public ReflectionContext CreateReflectionContext() + { + Assumes.NotNull<Type>(this._reflectionContextType); + + ReflectionContext reflectionContext = null; + try + { + reflectionContext = (ReflectionContext)Activator.CreateInstance(this._reflectionContextType); + } + catch (InvalidCastException invalidCastException) + { + throw new InvalidOperationException(Strings.ReflectionContext_Type_Required, invalidCastException); + } + catch (MissingMethodException missingMethodException) + { + throw new MissingMethodException(Strings.ReflectionContext_Requires_DefaultConstructor, missingMethodException); + } + + return reflectionContext; + } + } +} +#endif //FEATURE_REFLECTIONCONTEXT diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ChangeRejectedException.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ChangeRejectedException.cs new file mode 100644 index 00000000000..3f5da5c2225 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ChangeRejectedException.cs @@ -0,0 +1,69 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Security.Permissions; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// The exception that is thrown when one or more recoverable errors occur during + /// composition which results in those changes being rejected. + /// </summary> + [Serializable] + public class ChangeRejectedException : CompositionException + { + /// <summary> + /// Initializes a new instance of the <see cref="ChangeRejectedException"/> class. + /// </summary> + public ChangeRejectedException() + : this((string)null, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ChangeRejectedException"/> class. + /// </summary> + public ChangeRejectedException(string message) + : this(message, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ChangeRejectedException"/> class. + /// </summary> + public ChangeRejectedException(string message, Exception innerException) + : base(message, innerException, (IEnumerable<CompositionError>)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ChangeRejectedException"/> class. + /// </summary> + /// <param name="errors">List of errors that occured while applying the changes.</param> + public ChangeRejectedException(IEnumerable<CompositionError> errors) + : base((string)null, (Exception)null, errors) + { + } + + /// <summary> + /// Gets a message that describes the exception. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ChangeRejectedException"/>. + /// </value> + public override string Message + { + get + { + return string.Format(CultureInfo.CurrentCulture, + Strings.CompositionException_ChangesRejected, + base.Message); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionContractMismatchException.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionContractMismatchException.cs new file mode 100644 index 00000000000..4d15c1beb3c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionContractMismatchException.cs @@ -0,0 +1,90 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Runtime.Serialization; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// The exception that is thrown when the underlying exported value or metadata of an + /// <see cref="Lazy{T}"/> or <see cref="Lazy{T, TMetadataView}"/> object cannot be + /// cast to <c>T</c> or <c>TMetadataView</c>, respectively. + /// </summary> + [Serializable] + public class CompositionContractMismatchException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContractMismatchException"/> class. + /// </summary> + public CompositionContractMismatchException() + : this((string)null, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContractMismatchException"/> class + /// with the specified error message. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionContractMismatchException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + public CompositionContractMismatchException(string message) + : this(message, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContractMismatchException"/> class + /// with the specified error message and exception that is the cause of the + /// exception. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionContractMismatchException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + /// <param name="innerException"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="CompositionContractMismatchException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.InnerException"/> property to <see langword="null"/>. + /// </param> + public CompositionContractMismatchException(string message, Exception innerException) + : base(message, innerException) + { + } + +#if FEATURE_SERIALIZATION + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContractMismatchException"/> class + /// with the specified serialization data. + /// </summary> + /// <param name="info"> + /// The <see cref="SerializationInfo"/> that holds the serialized object data about the + /// <see cref="CompositionContractMismatchException"/>. + /// </param> + /// <param name="context"> + /// The <see cref="StreamingContext"/> that contains contextual information about the + /// source or destination. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="info"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="SerializationException"> + /// <paramref name="info"/> is missing a required value. + /// </exception> + /// <exception cref="InvalidCastException"> + /// <paramref name="info"/> contains a value that cannot be cast to the correct type. + /// </exception> + [System.Security.SecuritySafeCritical] + protected CompositionContractMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + +#endif + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionError.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionError.cs new file mode 100644 index 00000000000..c26b17b0853 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionError.cs @@ -0,0 +1,187 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Globalization; +using System.Security.Permissions; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Represents an error that occurs during composition. + /// </summary> + [Serializable] + [DebuggerTypeProxy(typeof(CompositionErrorDebuggerProxy))] + public class CompositionError + { + private readonly CompositionErrorId _id; + private readonly string _description; + private readonly Exception _exception; + + private readonly ICompositionElement _element; + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionError"/> class + /// with the specified error message. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set the + /// <see cref="Description"/> property to an empty string (""). + /// </param> + public CompositionError(string message) + : this(CompositionErrorId.Unknown, message, (ICompositionElement)null, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionError"/> class + /// with the specified error message and composition element that is the + /// cause of the composition error. + /// </summary> + /// <param name="element"> + /// The <see cref="ICompositionElement"/> that is the cause of the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set + /// the <see cref="CompositionError.Element"/> property to + /// <see langword="null"/>. + /// </param> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set the + /// <see cref="Description"/> property to an empty string (""). + /// </param> + public CompositionError(string message, ICompositionElement element) + : this(CompositionErrorId.Unknown, message, element, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionError"/> class + /// with the specified error message and exception that is the cause of the + /// composition error. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set the + /// <see cref="Description"/> property to an empty string (""). + /// </param> + /// <param name="exception"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set + /// the <see cref="CompositionError.Exception"/> property to <see langword="null"/>. + /// </param> + public CompositionError(string message, Exception exception) + : this(CompositionErrorId.Unknown, message, (ICompositionElement)null, exception) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionError"/> class + /// with the specified error message, and composition element and exception that + /// is the cause of the composition error. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set the + /// <see cref="Description"/> property to an empty string (""). + /// </param> + /// <param name="element"> + /// The <see cref="ICompositionElement"/> that is the cause of the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set + /// the <see cref="CompositionError.Element"/> property to + /// <see langword="null"/>. + /// </param> + /// <param name="exception"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="CompositionError"/>; or <see langword="null"/> to set + /// the <see cref="CompositionError.Exception"/> property to <see langword="null"/>. + /// </param> + public CompositionError(string message, ICompositionElement element, Exception exception) + : this(CompositionErrorId.Unknown, message, element, exception) + { + } + + internal CompositionError(CompositionErrorId id, string description, ICompositionElement element, Exception exception) + { + _id = id; + _description = description ?? string.Empty; + _element = element; + _exception = exception; + } + + /// <summary> + /// Gets the composition element that is the cause of the error. + /// </summary> + /// <value> + /// The <see cref="ICompositionElement"/> that is the cause of the + /// <see cref="CompositionError"/>. The default is <see langword="null"/>. + /// </value> + public ICompositionElement Element + { + get { return _element; } + } + + /// <summary> + /// Gets the message that describes the composition error. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionError"/>. + /// </value> + public string Description + { + get { return _description; } + } + + /// <summary> + /// Gets the exception that is the underlying cause of the composition error. + /// </summary> + /// <value> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="CompositionError"/>. The default is <see langword="null"/>. + /// </value> + public Exception Exception + { + get { return _exception; } + } + + internal CompositionErrorId Id + { + get { return _id; } + } + + internal Exception InnerException + { + get { return Exception; } + } + + /// <summary> + /// Returns a string representation of the composition error. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the <see cref="Description"/> property. + /// </returns> + public override string ToString() + { + return this.Description; + } + + internal static CompositionError Create(CompositionErrorId id, string format, params object[] parameters) + { + return Create(id, (ICompositionElement)null, (Exception)null, format, parameters); + } + + internal static CompositionError Create(CompositionErrorId id, ICompositionElement element, string format, params object[] parameters) + { + return Create(id, element, (Exception)null, format, parameters); + } + + internal static CompositionError Create(CompositionErrorId id, ICompositionElement element, Exception exception, string format, params object[] parameters) + { + return new CompositionError(id, string.Format(CultureInfo.CurrentCulture, format, parameters), element, exception); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionErrorDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionErrorDebuggerProxy.cs new file mode 100644 index 00000000000..9530adb74cd --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionErrorDebuggerProxy.cs @@ -0,0 +1,37 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal class CompositionErrorDebuggerProxy + { + private readonly CompositionError _error; + + public CompositionErrorDebuggerProxy(CompositionError error) + { + Requires.NotNull(error, "error"); + + this._error = error; + } + + public string Description + { + get { return this._error.Description; } + } + + public Exception Exception + { + get { return this._error.Exception; } + } + + public ICompositionElement Element + { + get { return this._error.Element; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionErrorId.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionErrorId.cs new file mode 100644 index 00000000000..cc02cd5c629 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionErrorId.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition +{ + internal enum CompositionErrorId : int + { + Unknown = 0, + InvalidExportMetadata, + ImportNotSetOnPart, + ImportEngine_ComposeTookTooManyIterations, + ImportEngine_ImportCardinalityMismatch, + ImportEngine_PartCycle, + ImportEngine_PartCannotSetImport, + ImportEngine_PartCannotGetExportedValue, + ImportEngine_PartCannotActivate, + ImportEngine_PreventedByExistingImport, + ImportEngine_InvalidStateForRecomposition, + ReflectionModel_ImportThrewException, + ReflectionModel_ImportNotAssignableFromExport, + ReflectionModel_ImportCollectionNull, + ReflectionModel_ImportCollectionNotWritable, + ReflectionModel_ImportCollectionConstructionThrewException, + ReflectionModel_ImportCollectionGetThrewException, + ReflectionModel_ImportCollectionIsReadOnlyThrewException, + ReflectionModel_ImportCollectionClearThrewException, + ReflectionModel_ImportCollectionAddThrewException, + ReflectionModel_ImportManyOnParameterCanOnlyBeAssigned, + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionException.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionException.cs new file mode 100644 index 00000000000..6bec825c4e1 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionException.cs @@ -0,0 +1,342 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Runtime.Serialization; +using System.Security.Permissions; +using System.Text; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition +{ + + /// <summary> + /// The exception that is thrown when one or more errors occur during composition. + /// </summary> + [Serializable] + [DebuggerTypeProxy(typeof(CompositionExceptionDebuggerProxy))] + [DebuggerDisplay("{Message}")] + public class CompositionException : Exception + { + const string ErrorsKey = "Errors"; + private ReadOnlyCollection<CompositionError> _errors; + +#if FEATURE_SERIALIZATION + [Serializable] + private struct CompositionExceptionData : ISafeSerializationData + { + public CompositionError[] _errors; + + void ISafeSerializationData.CompleteDeserialization(object obj) + { + CompositionException exception = obj as CompositionException; + + exception._errors = new ReadOnlyCollection<CompositionError>(this._errors); + } + } +#endif + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionException"/> class. + /// </summary> + public CompositionException() + : this((string)null, (Exception)null, (IEnumerable<CompositionError>)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionException"/> class + /// with the specified error message. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + public CompositionException(string message) + : this(message, (Exception)null, (IEnumerable<CompositionError>)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionException"/> class + /// with the specified error message and exception that is the cause of the + /// exception. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + /// <param name="innerException"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.InnerException"/> property to <see langword="null"/>. + /// </param> + public CompositionException(string message, Exception innerException) + : this(message, innerException, (IEnumerable<CompositionError>)null) + { + } + + internal CompositionException(CompositionError error) + : this(new CompositionError[] { error }) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionException"/> class + /// with the specified errors. + /// </summary> + /// <param name="errors"> + /// An <see cref="IEnumerable{T}"/> of <see cref="CompositionError"/> objects + /// representing the errors that are the cause of the + /// <see cref="CompositionException"/>; or <see langword="null"/> to set the + /// <see cref="Errors"/> property to an empty <see cref="IEnumerable{T}"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="errors"/> contains an element that is <see langword="null"/>. + /// </exception> + public CompositionException(IEnumerable<CompositionError> errors) + : this((string)null, (Exception)null, errors) + { + } + + + internal CompositionException(string message, Exception innerException, IEnumerable<CompositionError> errors) + : base(message, innerException) + { + Requires.NullOrNotNullElements(errors, "errors"); +#if FEATURE_SERIALIZATION + SerializeObjectState += delegate(object exception, SafeSerializationEventArgs eventArgs) + { + var data = new CompositionExceptionData(); + if(this._errors != null) + { + data._errors = this._errors.Select(error => new CompositionError( + error.Id, + error.Description, + error.Element.ToSerializableElement(), + error.Exception)).ToArray(); + } + else + { + data._errors = new CompositionError[0]; + } + + eventArgs.AddSerializedState(data); + }; +#endif + _errors = new ReadOnlyCollection<CompositionError>(errors == null ? new CompositionError[0] : errors.ToArray<CompositionError>()); + } + + /// <summary> + /// Gets the errors that are the cause of the exception. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="CompositionError"/> objects + /// representing the errors that are the cause of the + /// <see cref="CompositionException"/>. + /// </value> + public ReadOnlyCollection<CompositionError> Errors + { + get { return _errors; } + } + + + /// <summary> + /// Gets a message that describes the exception. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="CompositionException"/>. + /// </value> + public override string Message + { + get + { + if (this.Errors.Count == 0) + { // If there are no errors, then we simply return base.Message, + // which will either use the default Exception message, or if + // one was specified; the user supplied message. + + return base.Message; + } + + return BuildDefaultMessage(); + } + } + + private string BuildDefaultMessage() + { + IEnumerable<IEnumerable<CompositionError>> paths = CalculatePaths(this); + + StringBuilder writer = new StringBuilder(); + + WriteHeader(writer, this.Errors.Count, paths.Count()); + WritePaths(writer, paths); + + return writer.ToString(); + } + + private static void WriteHeader(StringBuilder writer, int errorsCount, int pathCount) + { + if (errorsCount > 1 && pathCount > 1) + { + // The composition produced multiple composition errors, with {0} root causes. The root causes are provided below. + writer.AppendFormat( + CultureInfo.CurrentCulture, + Strings.CompositionException_MultipleErrorsWithMultiplePaths, + pathCount); + } + else if (errorsCount == 1 && pathCount > 1) + { + // The composition produced a single composition error, with {0} root causes. The root causes are provided below. + writer.AppendFormat( + CultureInfo.CurrentCulture, + Strings.CompositionException_SingleErrorWithMultiplePaths, + pathCount); + } + else + { + Assumes.IsTrue(errorsCount == 1); + Assumes.IsTrue(pathCount == 1); + + // The composition produced a single composition error. The root cause is provided below. + writer.AppendFormat( + CultureInfo.CurrentCulture, + Strings.CompositionException_SingleErrorWithSinglePath, + pathCount); + } + + writer.Append(' '); + writer.AppendLine(Strings.CompositionException_ReviewErrorProperty); + } + + private static void WritePaths(StringBuilder writer, IEnumerable<IEnumerable<CompositionError>> paths) + { + int ordinal = 0; + foreach (IEnumerable<CompositionError> path in paths) + { + ordinal++; + WritePath(writer, path, ordinal); + } + } + + private static void WritePath(StringBuilder writer, IEnumerable<CompositionError> path, int ordinal) + { + writer.AppendLine(); + writer.Append(ordinal.ToString(CultureInfo.CurrentCulture)); + writer.Append(Strings.CompositionException_PathsCountSeparator); + writer.Append(' '); + + WriteError(writer, path.First()); + + foreach (CompositionError error in path.Skip(1)) + { + writer.AppendLine(); + writer.Append(Strings.CompositionException_ErrorPrefix); + writer.Append(' '); + WriteError(writer, error); + } + } + + private static void WriteError(StringBuilder writer, CompositionError error) + { + writer.AppendLine(error.Description); + + if (error.Element != null) + { + WriteElementGraph(writer, error.Element); + } + } + + private static void WriteElementGraph(StringBuilder writer, ICompositionElement element) + { + // Writes the composition element and its origins in the format: + // Element: Export --> Part --> PartDefinition --> Catalog + + writer.AppendFormat(CultureInfo.CurrentCulture, Strings.CompositionException_ElementPrefix, element.DisplayName); + + while ((element = element.Origin) != null) + { + writer.AppendFormat(CultureInfo.CurrentCulture, Strings.CompositionException_OriginFormat, Strings.CompositionException_OriginSeparator, element.DisplayName); + } + + writer.AppendLine(); + } + + private static IEnumerable<IEnumerable<CompositionError>> CalculatePaths(CompositionException exception) + { + List<IEnumerable<CompositionError>> paths = new List<IEnumerable<CompositionError>>(); + + VisitContext context = new VisitContext(); + context.Path = new Stack<CompositionError>(); + context.LeafVisitor = path => + { + // Take a snapshot of the path + paths.Add(path.Copy()); + }; + + VisitCompositionException(exception, context); + + return paths; + } + + private static void VisitCompositionException(CompositionException exception, VisitContext context) + { + foreach (CompositionError error in exception.Errors) + { + VisitError(error, context); + } + + if (exception.InnerException != null) + { + VisitException(exception.InnerException, context); + } + } + + private static void VisitError(CompositionError error, VisitContext context) + { + context.Path.Push(error); + + if (error.Exception == null) + { // This error is a root cause, so write + // out the stack from this point + + context.LeafVisitor(context.Path); + } + else + { + VisitException(error.Exception, context); + } + + context.Path.Pop(); + } + + private static void VisitException(Exception exception, VisitContext context) + { + CompositionException composition = exception as CompositionException; + if (composition != null) + { + VisitCompositionException(composition, context); + } + else + { + VisitError(new CompositionError(exception.Message, exception.InnerException), context); + } + } + + private struct VisitContext + { + public Stack<CompositionError> Path; + public Action<Stack<CompositionError>> LeafVisitor; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionExceptionDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionExceptionDebuggerProxy.cs new file mode 100644 index 00000000000..1db7863e409 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionExceptionDebuggerProxy.cs @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Reflection; + +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition +{ + internal class CompositionExceptionDebuggerProxy + { + private readonly CompositionException _exception; + + public CompositionExceptionDebuggerProxy(CompositionException exception) + { + Requires.NotNull(exception, "exception"); + + this._exception = exception; + } + + public ReadOnlyCollection<Exception> Exceptions + { + get + { + var errors = new List<Exception>(); + + // In here return a collection of all of the exceptions in the Errors collection + foreach (var error in _exception.Errors) + { + if (error.Exception != null) + { + errors.Add(error.Exception); + } + } + return errors.ToReadOnlyCollection<Exception>(); + } + } + + public string Message + { + get { return _exception.Message; } + } + + public ReadOnlyCollection<Exception> RootCauses + { + get + { + var errors = new List<Exception>(); + + // In here return a collection of all of the exceptions in the Errors collection + foreach (var error in _exception.Errors) + { + if (error.Exception != null) + { + var ce = error.Exception as CompositionException; + if (ce != null) + { + var ceProxy = new CompositionExceptionDebuggerProxy(ce); + if (ceProxy.RootCauses.Count > 0) + { + errors.AddRange(ceProxy.RootCauses); + continue; + } + } + errors.Add(error.Exception); + } + } + return errors.ToReadOnlyCollection<Exception>(); + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionResult.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionResult.cs new file mode 100644 index 00000000000..f8c3c492ea3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionResult.cs @@ -0,0 +1,86 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.Internal.Collections; +using System.ComponentModel.Composition.Hosting; + +namespace System.ComponentModel.Composition +{ + internal struct CompositionResult + { + public static readonly CompositionResult SucceededResult = new CompositionResult(); + private readonly IEnumerable<CompositionError> _errors; + + public CompositionResult(params CompositionError[] errors) + : this((IEnumerable<CompositionError>)errors) + { + } + + public CompositionResult(IEnumerable<CompositionError> errors) + { + this._errors = errors; + } + + public bool Succeeded + { + get { return this._errors == null || !this._errors.FastAny(); } + } + + public IEnumerable<CompositionError> Errors + { + get { return this._errors ?? Enumerable.Empty<CompositionError>(); } + } + + public CompositionResult MergeResult(CompositionResult result) + { + if (this.Succeeded) + { + return result; + } + if (result.Succeeded) + { + return this; + } + return MergeErrors(result._errors); + } + + public CompositionResult MergeError(CompositionError error) + { + return MergeErrors(new CompositionError[] { error }); + } + + public CompositionResult MergeErrors(IEnumerable<CompositionError> errors) + { + return new CompositionResult(this._errors.ConcatAllowingNull(errors)); + } + + public CompositionResult<T> ToResult<T>(T value) + { + return new CompositionResult<T>(value, this._errors); + } + + public void ThrowOnErrors() + { + ThrowOnErrors(null); + } + + public void ThrowOnErrors(AtomicComposition atomicComposition) + { + if (!this.Succeeded) + { + if (atomicComposition == null) + { + throw new CompositionException(this._errors); + } + else + { + throw new ChangeRejectedException(this._errors); + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionResultOfT.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionResultOfT.cs new file mode 100644 index 00000000000..65ee76df047 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CompositionResultOfT.cs @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition +{ + internal struct CompositionResult<T> + { + private readonly IEnumerable<CompositionError> _errors; + private readonly T _value; + + public CompositionResult(T value) + : this(value, (CompositionError[])null) + { + } + + public CompositionResult(params CompositionError[] errors) + : this(default(T), (IEnumerable<CompositionError>)errors) + { + } + + public CompositionResult(IEnumerable<CompositionError> errors) + : this(default(T), errors) + { + } + + internal CompositionResult(T value, IEnumerable<CompositionError> errors) + { + this._errors = errors; + this._value = value; + } + + public bool Succeeded + { + get { return this._errors == null || !this._errors.FastAny(); } + } + + public IEnumerable<CompositionError> Errors + { + get { return this._errors ?? Enumerable.Empty<CompositionError>(); } + } + + /// <summary> + /// Gets the value from the result, throwing a CompositionException if there are any errors. + /// </summary> + public T Value + { + get + { + ThrowOnErrors(); + + return this._value; + } + } + + internal CompositionResult<TValue> ToResult<TValue>() + { + return new CompositionResult<TValue>(this._errors); + } + + internal CompositionResult ToResult() + { + return new CompositionResult(this._errors); + } + + private void ThrowOnErrors() + { + if (!this.Succeeded) + { + throw new CompositionException(this._errors); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ConstraintServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ConstraintServices.cs new file mode 100644 index 00000000000..ebe2b6ca97d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ConstraintServices.cs @@ -0,0 +1,196 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal static class ConstraintServices + { + // NOTE : these are here as Reflection member search is pretty expensive, and we want that to be done once. + // Also, making these static would cause this class to fail loading if we rename members of ExportDefinition. + private static readonly PropertyInfo _exportDefinitionContractNameProperty = typeof(ExportDefinition).GetProperty("ContractName"); + private static readonly PropertyInfo _exportDefinitionMetadataProperty = typeof(ExportDefinition).GetProperty("Metadata"); + private static readonly MethodInfo _metadataContainsKeyMethod = typeof(IDictionary<string, object>).GetMethod("ContainsKey"); + private static readonly MethodInfo _metadataItemMethod = typeof(IDictionary<string, object>).GetMethod("get_Item"); + private static readonly MethodInfo _metadataEqualsMethod = typeof(object).GetMethod("Equals", new Type[] { typeof(object) }); + private static readonly MethodInfo _typeIsInstanceOfTypeMethod = typeof(Type).GetMethod("IsInstanceOfType"); + + public static Expression<Func<ExportDefinition, bool>> CreateConstraint(string contractName, string requiredTypeIdentity, IEnumerable<KeyValuePair<string, Type>> requiredMetadata, CreationPolicy requiredCreationPolicy) + { + ParameterExpression parameter = Expression.Parameter(typeof(ExportDefinition), "exportDefinition"); + + Expression constraintBody = ConstraintServices.CreateContractConstraintBody(contractName, parameter); + + if (!string.IsNullOrEmpty(requiredTypeIdentity)) + { + Expression typeIdentityConstraintBody = ConstraintServices.CreateTypeIdentityContraint(requiredTypeIdentity, parameter); + + constraintBody = Expression.AndAlso(constraintBody, typeIdentityConstraintBody); + } + + if (requiredMetadata != null) + { + Expression metadataConstraintBody = ConstraintServices.CreateMetadataConstraintBody(requiredMetadata, parameter); + if (metadataConstraintBody != null) + { + constraintBody = Expression.AndAlso(constraintBody, metadataConstraintBody); + } + } + + if (requiredCreationPolicy != CreationPolicy.Any) + { + Expression policyConstraintBody = ConstraintServices.CreateCreationPolicyContraint(requiredCreationPolicy, parameter); + + constraintBody = Expression.AndAlso(constraintBody, policyConstraintBody); + } + + Expression<Func<ExportDefinition, bool>> constraint = Expression.Lambda<Func<ExportDefinition, bool>>(constraintBody, parameter); + return constraint; + } + + private static Expression CreateContractConstraintBody(string contractName, ParameterExpression parameter) + { + Assumes.NotNull(parameter); + + // export.ContractName=<contract>; + return Expression.Equal( + Expression.Property(parameter, ConstraintServices._exportDefinitionContractNameProperty), + Expression.Constant(contractName ?? string.Empty, typeof(string))); + } + + private static Expression CreateMetadataConstraintBody(IEnumerable<KeyValuePair<string, Type>> requiredMetadata, ParameterExpression parameter) + { + Assumes.NotNull(requiredMetadata); + Assumes.NotNull(parameter); + + Expression body = null; + foreach (KeyValuePair<string, Type> requiredMetadataItem in requiredMetadata) + { + // export.Metadata.ContainsKey(<metadataItem>) + Expression metadataItemExpression = CreateMetadataContainsKeyExpression(parameter, requiredMetadataItem.Key); + + body = (body != null) ? Expression.AndAlso(body, metadataItemExpression) : metadataItemExpression; + body = Expression.AndAlso(body, CreateMetadataOfTypeExpression(parameter, requiredMetadataItem.Key, requiredMetadataItem.Value)); + } + + return body; + } + + private static Expression CreateCreationPolicyContraint(CreationPolicy policy, ParameterExpression parameter) + { + Assumes.IsTrue(policy != CreationPolicy.Any); + Assumes.NotNull(parameter); + + // !definition.Metadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName) || + // CreationPolicy.Any.Equals(definition.Metadata[CompositionConstants.PartCreationPolicyMetadataName]) || + // policy.Equals(definition.Metadata[CompositionConstants.PartCreationPolicyMetadataName]); + + return Expression.MakeBinary(ExpressionType.OrElse, + Expression.MakeBinary(ExpressionType.OrElse, + Expression.Not(CreateMetadataContainsKeyExpression(parameter, CompositionConstants.PartCreationPolicyMetadataName)), + CreateMetadataValueEqualsExpression(parameter, CreationPolicy.Any, CompositionConstants.PartCreationPolicyMetadataName)), + CreateMetadataValueEqualsExpression(parameter, policy, CompositionConstants.PartCreationPolicyMetadataName)); + } + + private static Expression CreateTypeIdentityContraint(string requiredTypeIdentity, ParameterExpression parameter) + { + Assumes.NotNull(requiredTypeIdentity); + Assumes.NotNull(parameter); + + // definition.Metadata.ContainsKey(CompositionServices.ExportTypeIdentity) && + // requiredTypeIdentity.Equals(definition.Metadata[CompositionConstants.ExportTypeIdentityMetadataName]); + + return Expression.MakeBinary(ExpressionType.AndAlso, + CreateMetadataContainsKeyExpression(parameter, CompositionConstants.ExportTypeIdentityMetadataName), + CreateMetadataValueEqualsExpression(parameter, requiredTypeIdentity, CompositionConstants.ExportTypeIdentityMetadataName)); + } + + private static Expression CreateMetadataContainsKeyExpression(ParameterExpression parameter, string constantKey) + { + Assumes.NotNull(parameter, constantKey); + + // definition.Metadata.ContainsKey(constantKey) + return Expression.Call( + Expression.Property(parameter, ConstraintServices._exportDefinitionMetadataProperty), + ConstraintServices._metadataContainsKeyMethod, + Expression.Constant(constantKey)); + } + + private static Expression CreateMetadataOfTypeExpression(ParameterExpression parameter, string constantKey, Type constantType) + { + Assumes.NotNull(parameter, constantKey); + Assumes.NotNull(parameter, constantType); + + // constantType.IsInstanceOfType(definition.Metadata[constantKey]) + return Expression.Call( + Expression.Constant(constantType, typeof(Type)), + ConstraintServices._typeIsInstanceOfTypeMethod, + Expression.Call( + Expression.Property(parameter, ConstraintServices._exportDefinitionMetadataProperty), + ConstraintServices._metadataItemMethod, + Expression.Constant(constantKey)) + ); + } + + private static Expression CreateMetadataValueEqualsExpression(ParameterExpression parameter, object constantValue, string metadataName) + { + Assumes.NotNull(parameter, constantValue); + + // constantValue.Equals(definition.Metadata[CompositionServices.PartCreationPolicyMetadataName]) + return Expression.Call( + Expression.Constant(constantValue), + ConstraintServices._metadataEqualsMethod, + Expression.Call( + Expression.Property(parameter, ConstraintServices._exportDefinitionMetadataProperty), + ConstraintServices._metadataItemMethod, + Expression.Constant(metadataName))); + } + + public static Expression<Func<ExportDefinition, bool>> CreatePartCreatorConstraint(Expression<Func<ExportDefinition, bool>> baseConstraint, ImportDefinition productImportDefinition) + { + ParameterExpression exportDefinitionParameter = baseConstraint.Parameters[0]; + + // exportDefinition.Metadata + Expression metadataExpression = Expression.Property(exportDefinitionParameter, ConstraintServices._exportDefinitionMetadataProperty); + + // exportDefinition.Metadata.ContainsKey("ProductDefinition") + Expression containsProductExpression = Expression.Call( + metadataExpression, + ConstraintServices._metadataContainsKeyMethod, + Expression.Constant(CompositionConstants.ProductDefinitionMetadataName)); + + // exportDefinition.Metadata["ProductDefinition"] + Expression productExportDefinitionExpression = Expression.Call( + metadataExpression, + ConstraintServices._metadataItemMethod, + Expression.Constant(CompositionConstants.ProductDefinitionMetadataName)); + + // ProductImportDefinition.Contraint((ExportDefinition)exportDefinition.Metadata["ProductDefinition"]) + Expression productMatchExpression = + Expression.Invoke(productImportDefinition.Constraint, + Expression.Convert(productExportDefinitionExpression, typeof(ExportDefinition))); + + // baseContraint(exportDefinition) && + // exportDefinition.Metadata.ContainsKey("ProductDefinition") && + // ProductImportDefinition.Contraint((ExportDefinition)exportDefinition.Metadata["ProductDefinition"]) + Expression<Func<ExportDefinition, bool>> constraint = + Expression.Lambda<Func<ExportDefinition, bool>>( + Expression.AndAlso( + baseConstraint.Body, + Expression.AndAlso( + containsProductExpression, + productMatchExpression)), + exportDefinitionParameter); + + return constraint; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ContractNameServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ContractNameServices.cs new file mode 100644 index 00000000000..962e172947c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ContractNameServices.cs @@ -0,0 +1,342 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Text; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal static class ContractNameServices + { + const char NamespaceSeparator = '.'; + const char ArrayOpeningBracket = '['; + const char ArrayClosingBracket = ']'; + const char ArraySeparator = ','; + const char PointerSymbol = '*'; + const char ReferenceSymbol = '&'; + const char GenericArityBackQuote = '`'; + const char NestedClassSeparator = '+'; + const char ContractNameGenericOpeningBracket = '('; + const char ContractNameGenericClosingBracket = ')'; + const char ContractNameGenericArgumentSeparator = ','; + const char CustomModifiersSeparator = ' '; + const char GenericFormatOpeningBracket = '{'; + const char GenericFormatClosingBracket = '}'; + + [ThreadStatic] + private static Dictionary<Type, string> typeIdentityCache; + + private static Dictionary<Type, string> TypeIdentityCache + { + get + { + return typeIdentityCache = typeIdentityCache ?? new Dictionary<Type, string>(); + } + } + + internal static string GetTypeIdentity(Type type) + { + return GetTypeIdentity(type, true); + } + + internal static string GetTypeIdentity(Type type, bool formatGenericName) + { + Assumes.NotNull(type); + string typeIdentity = null; + + if (!TypeIdentityCache.TryGetValue(type, out typeIdentity)) + { + if (!type.IsAbstract && type.IsSubclassOf(typeof(Delegate))) + { + MethodInfo method = type.GetMethod("Invoke"); + typeIdentity = ContractNameServices.GetTypeIdentityFromMethod(method); + } + else if (type.IsGenericParameter) + { + StringBuilder typeIdentityStringBuilder = new StringBuilder(); + WriteTypeArgument(typeIdentityStringBuilder, false, type, formatGenericName); + typeIdentityStringBuilder.Remove(typeIdentityStringBuilder.Length - 1, 1); + typeIdentity = typeIdentityStringBuilder.ToString(); + } + else + { + StringBuilder typeIdentityStringBuilder = new StringBuilder(); + WriteTypeWithNamespace(typeIdentityStringBuilder, type, formatGenericName); + typeIdentity = typeIdentityStringBuilder.ToString(); + } + + Assumes.IsTrue(!string.IsNullOrEmpty(typeIdentity)); + TypeIdentityCache.Add(type, typeIdentity); + } + + return typeIdentity; + } + + internal static string GetTypeIdentityFromMethod(MethodInfo method) + { + return GetTypeIdentityFromMethod(method, true); + } + + internal static string GetTypeIdentityFromMethod(MethodInfo method, bool formatGenericName) + { + StringBuilder methodNameStringBuilder = new StringBuilder(); + + WriteTypeWithNamespace(methodNameStringBuilder, method.ReturnType, formatGenericName); + + methodNameStringBuilder.Append("("); + + ParameterInfo[] parameters = method.GetParameters(); + + for (int i = 0; i < parameters.Length; i++) + { + if (i != 0) + { + methodNameStringBuilder.Append(","); + } + + WriteTypeWithNamespace(methodNameStringBuilder, parameters[i].ParameterType, formatGenericName); + } + methodNameStringBuilder.Append(")"); + + return methodNameStringBuilder.ToString(); + } + + private static void WriteTypeWithNamespace(StringBuilder typeName, Type type, bool formatGenericName) + { + // Writes type with namesapce + if (!string.IsNullOrEmpty(type.Namespace)) + { + typeName.Append(type.Namespace); + typeName.Append(NamespaceSeparator); + } + WriteType(typeName, type, formatGenericName); + } + + private static void WriteType(StringBuilder typeName, Type type, bool formatGenericName) + { + // Writes type name + if (type.IsGenericType) + { + // + // Reflection format stores all the generic arguments (including the ones for parent types) on the leaf type. + // These arguments are placed in a queue and are written out based on generic arity (`X) of each type + // + Queue<Type> genericTypeArguments = new Queue<Type>(type.GetGenericArguments()); + WriteGenericType(typeName, type, type.IsGenericTypeDefinition, genericTypeArguments, formatGenericName); + Assumes.IsTrue(genericTypeArguments.Count == 0, "Expecting genericTypeArguments queue to be empty."); + } + else + { + WriteNonGenericType(typeName, type, formatGenericName); + } + } + + private static void WriteNonGenericType(StringBuilder typeName, Type type, bool formatGenericName) + { + // + // Writes non-generic type + // + if (type.DeclaringType != null) + { + WriteType(typeName, type.DeclaringType, formatGenericName); + typeName.Append(NestedClassSeparator); + } + if (type.IsArray) + { + WriteArrayType(typeName, type, formatGenericName); + } + else if (type.IsPointer) + { + WritePointerType(typeName, type, formatGenericName); + } + else if (type.IsByRef) + { + WriteByRefType(typeName, type, formatGenericName); + } + else + { + typeName.Append(type.Name); + } + } + + private static void WriteArrayType(StringBuilder typeName, Type type, bool formatGenericName) + { + // + // Writes array type e.g <TypeName>[] + // Note that jagged arrays are stored in reverse order + // e.g. C#: Int32[][,] Reflection: Int32[,][] + // we are following C# order for arrays + // + Type rootElementType = FindArrayElementType(type); + WriteType(typeName, rootElementType, formatGenericName); + Type elementType = type; + do + { + WriteArrayTypeDimensions(typeName, elementType); + } + while ((elementType = elementType.GetElementType()) != null && elementType.IsArray); + } + + private static void WritePointerType(StringBuilder typeName, Type type, bool formatGenericName) + { + // + // Writes pointer type e.g <TypeName>* + // + WriteType(typeName, type.GetElementType(), formatGenericName); + typeName.Append(PointerSymbol); + } + + private static void WriteByRefType(StringBuilder typeName, Type type, bool formatGenericName) + { + // + // Writes by ref type e.g <TypeName>& + // + WriteType(typeName, type.GetElementType(), formatGenericName); + typeName.Append(ReferenceSymbol); + } + + private static void WriteArrayTypeDimensions(StringBuilder typeName, Type type) + { + // + // Writes array type dimensions e.g. [,,] + // + typeName.Append(ArrayOpeningBracket); + int rank = type.GetArrayRank(); + for (int i = 1; i < rank; i++) + { + typeName.Append(ArraySeparator); + } + typeName.Append(ArrayClosingBracket); + } + + private static void WriteGenericType(StringBuilder typeName, Type type, bool isDefinition, Queue<Type> genericTypeArguments, bool formatGenericName) + { + // + // Writes generic type including parent generic types + // genericTypeArguments contains type arguments obtained from the most nested type + // isDefinition parameter indicates if we are dealing with generic type definition + // + if (type.DeclaringType != null) + { + if (type.DeclaringType.IsGenericType) + { + WriteGenericType(typeName, type.DeclaringType, isDefinition, genericTypeArguments, formatGenericName); + } + else + { + WriteNonGenericType(typeName, type.DeclaringType, formatGenericName); + } + typeName.Append(NestedClassSeparator); + } + WriteGenericTypeName(typeName, type, isDefinition, genericTypeArguments, formatGenericName); + } + + private static void WriteGenericTypeName(StringBuilder typeName, Type type, bool isDefinition, Queue<Type> genericTypeArguments, bool formatGenericName) + { + // + // Writes generic type name, e.g. generic name and generic arguments + // + Assumes.IsTrue(type.IsGenericType, "Expecting type to be a generic type"); + int genericArity = GetGenericArity(type); + string genericTypeName = FindGenericTypeName(type.GetGenericTypeDefinition().Name); + typeName.Append(genericTypeName); + WriteTypeArgumentsString(typeName, genericArity, isDefinition, genericTypeArguments, formatGenericName); + } + + private static void WriteTypeArgumentsString(StringBuilder typeName, int argumentsCount, bool isDefinition, Queue<Type> genericTypeArguments, bool formatGenericName) + { + // + // Writes type arguments in brackets, e.g. (<contract_name1>, <contract_name2>, ...) + // + if (argumentsCount == 0) + { + return; + } + typeName.Append(ContractNameGenericOpeningBracket); + for (int i = 0; i < argumentsCount; i++) + { + Assumes.IsTrue(genericTypeArguments.Count > 0, "Expecting genericTypeArguments to contain at least one Type"); + Type genericTypeArgument = genericTypeArguments.Dequeue(); + WriteTypeArgument(typeName, isDefinition, genericTypeArgument, formatGenericName); + } + typeName.Remove(typeName.Length - 1, 1); + typeName.Append(ContractNameGenericClosingBracket); + } + + private static void WriteTypeArgument(StringBuilder typeName, bool isDefinition, Type genericTypeArgument, bool formatGenericName) + { + if (!isDefinition && !genericTypeArgument.IsGenericParameter) + { + WriteTypeWithNamespace(typeName, genericTypeArgument, formatGenericName); + } + + if (formatGenericName && genericTypeArgument.IsGenericParameter) + { + typeName.Append(GenericFormatOpeningBracket); + typeName.Append(genericTypeArgument.GenericParameterPosition); + typeName.Append(GenericFormatClosingBracket); + } + typeName.Append(ContractNameGenericArgumentSeparator); + } + + //internal for testability + internal static void WriteCustomModifiers(StringBuilder typeName, string customKeyword, Type[] types, bool formatGenericName) + { + // + // Writes custom modifiers in the format: customKeyword(<contract_name>,<contract_name>,...) + // + typeName.Append(CustomModifiersSeparator); + typeName.Append(customKeyword); + Queue<Type> typeArguments = new Queue<Type>(types); + WriteTypeArgumentsString(typeName, types.Length, false, typeArguments, formatGenericName); + Assumes.IsTrue(typeArguments.Count == 0, "Expecting genericTypeArguments queue to be empty."); + } + + private static Type FindArrayElementType(Type type) + { + // + // Gets array element type by calling GetElementType() until the element is not an array + // + Type elementType = type; + while ((elementType = elementType.GetElementType()) != null && elementType.IsArray) { } + return elementType; + } + + private static string FindGenericTypeName(string genericName) + { + // + // Gets generic type name omitting the backquote and arity indicator + // List`1 -> List + // Arity indicator is returned as output parameter + // + int indexOfBackQuote = genericName.IndexOf(GenericArityBackQuote); + if (indexOfBackQuote > -1) + { + genericName = genericName.Substring(0, indexOfBackQuote); + } + return genericName; + } + + private static int GetGenericArity(Type type) + { + if (type.DeclaringType == null) + { + return type.GetGenericArguments().Length; + } + + // The generic arity is equal to the difference in the number of generic arguments + // from the type and the declaring type. + + int delclaringTypeGenericArguments = type.DeclaringType.GetGenericArguments().Length; + int typeGenericArguments = type.GetGenericArguments().Length; + + Assumes.IsTrue(typeGenericArguments >= delclaringTypeGenericArguments); + + return typeGenericArguments - delclaringTypeGenericArguments; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CreationPolicy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CreationPolicy.cs new file mode 100644 index 00000000000..13302bb3ea6 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/CreationPolicy.cs @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Option placed on a type that controls when the <see cref="CompositionContainer"/> creates + /// a new instance of a <see cref="ComposablePart"/>. + /// </summary> + public enum CreationPolicy : int + { + /// <summary> + /// Let the <see cref="CompositionContainer"/> choose the most appropriate <see cref="CreationPolicy"/> + /// for the part given the current context. This is the default <see cref="CreationPolicy"/>, with + /// the <see cref="CompositionContainer"/> choosing <see cref="CreationPolicy.Shared"/> by default + /// unless the <see cref="ComposablePart"/> or importer requests <see cref="CreationPolicy.NonShared"/>. + /// </summary> + Any = 0, + + /// <summary> + /// A single shared instance of the associated <see cref="ComposablePart"/> will be created + /// by the <see cref="CompositionContainer"/> and shared by all requestors. + /// </summary> + Shared = 1, + + /// <summary> + /// A new non-shared instance of the associated <see cref="ComposablePart"/> will be created + /// by the <see cref="CompositionContainer"/> for every requestor. + /// </summary> + NonShared = 2, + + /// <summary> + /// Each new non-shared instance of the part is created by a new <see cref="CompositionContainer"/> for every requestor. Shared instances of the parts dependencies + /// are unique to this instance. + /// For this release can only be applied to imports of type <see cref="ExportFactory<T>"/> + /// </summary> + NewScope = 3, + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTrace.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTrace.cs new file mode 100644 index 00000000000..2f8e56bfeb1 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTrace.cs @@ -0,0 +1,108 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using Microsoft.Internal; +using System.Reflection; + +namespace System.ComponentModel.Composition.Diagnostics +{ + internal static class CompositionTrace + { + internal static void PartDefinitionResurrected(ComposablePartDefinition definition) + { + Assumes.NotNull(definition); + + if (CompositionTraceSource.CanWriteInformation) + { + CompositionTraceSource.WriteInformation(CompositionTraceId.Rejection_DefinitionResurrected, + Strings.CompositionTrace_Rejection_DefinitionResurrected, + definition.GetDisplayName()); + } + } + + internal static void PartDefinitionRejected(ComposablePartDefinition definition, ChangeRejectedException exception) + { + Assumes.NotNull(definition, exception); + + if (CompositionTraceSource.CanWriteWarning) + { + CompositionTraceSource.WriteWarning(CompositionTraceId.Rejection_DefinitionRejected, + Strings.CompositionTrace_Rejection_DefinitionRejected, + definition.GetDisplayName(), + exception.Message); + } + } + +#if FEATURE_REFLECTIONFILEIO + + internal static void AssemblyLoadFailed(DirectoryCatalog catalog, string fileName, Exception exception) + { + Assumes.NotNull(catalog, exception); + Assumes.NotNullOrEmpty(fileName); + + if (CompositionTraceSource.CanWriteWarning) + { + CompositionTraceSource.WriteWarning(CompositionTraceId.Discovery_AssemblyLoadFailed, + Strings.CompositionTrace_Discovery_AssemblyLoadFailed, + catalog.GetDisplayName(), + fileName, + exception.Message); + } + } + +#endif //FEATURE_REFLECTIONFILEIO + + internal static void DefinitionMarkedWithPartNotDiscoverableAttribute(Type type) + { + Assumes.NotNull(type); + + if (CompositionTraceSource.CanWriteInformation) + { + CompositionTraceSource.WriteInformation(CompositionTraceId.Discovery_DefinitionMarkedWithPartNotDiscoverableAttribute, + Strings.CompositionTrace_Discovery_DefinitionMarkedWithPartNotDiscoverableAttribute, + type.GetDisplayName()); + } + } + + internal static void DefinitionMismatchedExportArity(Type type, MemberInfo member) + { + Assumes.NotNull(type); + Assumes.NotNull(member); + + if (CompositionTraceSource.CanWriteInformation) + { + CompositionTraceSource.WriteInformation(CompositionTraceId.Discovery_DefinitionMismatchedExportArity, + Strings.CompositionTrace_Discovery_DefinitionMismatchedExportArity, + type.GetDisplayName(), member.GetDisplayName()); + } + } + + internal static void DefinitionContainsNoExports(Type type) + { + Assumes.NotNull(type); + + if (CompositionTraceSource.CanWriteInformation) + { + CompositionTraceSource.WriteInformation(CompositionTraceId.Discovery_DefinitionContainsNoExports, + Strings.CompositionTrace_Discovery_DefinitionContainsNoExports, + type.GetDisplayName()); + } + } + + internal static void MemberMarkedWithMultipleImportAndImportMany(ReflectionItem item) + { + Assumes.NotNull(item); + + if (CompositionTraceSource.CanWriteError) + { + CompositionTraceSource.WriteError(CompositionTraceId.Discovery_MemberMarkedWithMultipleImportAndImportMany, + Strings.CompositionTrace_Discovery_MemberMarkedWithMultipleImportAndImportMany, + item.GetDisplayName()); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTraceId.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTraceId.cs new file mode 100644 index 00000000000..7c8a0ac2646 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTraceId.cs @@ -0,0 +1,24 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition.Diagnostics +{ + // NOTE: Do not change the trace ids of values that have already shipped, + // these leak out to TraceListerners which could take a dependency on them. + // This enum is a ushort deliberately, the maximum value of a trace id is 65535. + internal enum CompositionTraceId : ushort + { + // Rejection + + Rejection_DefinitionRejected = 1, + Rejection_DefinitionResurrected = 2, + + Discovery_AssemblyLoadFailed = 3, + Discovery_DefinitionMarkedWithPartNotDiscoverableAttribute = 4, + Discovery_DefinitionMismatchedExportArity = 5, + Discovery_DefinitionContainsNoExports = 6, + Discovery_MemberMarkedWithMultipleImportAndImportMany = 7, + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTraceSource.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTraceSource.cs new file mode 100644 index 00000000000..ddf2f34ae3e --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/CompositionTraceSource.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Diagnostics +{ + internal static class CompositionTraceSource + { +#if FEATURE_TRACING + private static readonly TraceSourceTraceWriter Source = new TraceSourceTraceWriter(); +#else + private static readonly DebuggerTraceWriter Source = new DebuggerTraceWriter(); +#endif + + public static bool CanWriteInformation + { + get { return Source.CanWriteInformation; } + } + + public static bool CanWriteWarning + { + get { return Source.CanWriteWarning; } + } + + public static bool CanWriteError + { + get { return Source.CanWriteError; } + } + + public static void WriteInformation(CompositionTraceId traceId, string format, params object[] arguments) + { + EnsureEnabled(CanWriteInformation); + + Source.WriteInformation(traceId, format, arguments); + } + + public static void WriteWarning(CompositionTraceId traceId, string format, params object[] arguments) + { + EnsureEnabled(CanWriteWarning); + + Source.WriteWarning(traceId, format, arguments); + } + + public static void WriteError(CompositionTraceId traceId, string format, params object[] arguments) + { + EnsureEnabled(CanWriteError); + + Source.WriteError(traceId, format, arguments); + } + + private static void EnsureEnabled(bool condition) + { + Assumes.IsTrue(condition, "To avoid unnecessary work when a trace level has not been enabled, check CanWriteXXX before calling this method."); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/SilverlightTraceWriter.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/SilverlightTraceWriter.cs new file mode 100644 index 00000000000..2a1e1fec124 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/SilverlightTraceWriter.cs @@ -0,0 +1,89 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +#if !FEATURE_TRACING +using System; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +namespace System.ComponentModel.Composition.Diagnostics +{ + internal sealed class DebuggerTraceWriter : TraceWriter + { + private static readonly string SourceName = "System.ComponentModel.Composition"; + + public override bool CanWriteInformation + { + get { return false; } + } + + public override bool CanWriteWarning + { + get { return Debugger.IsLogging(); } + } + + public override bool CanWriteError + { + get { return Debugger.IsLogging(); } + } + + public override void WriteInformation(CompositionTraceId traceId, string format, params object[] arguments) + { + WriteEvent(TraceEventType.Information, traceId, format, arguments); + } + + public override void WriteWarning(CompositionTraceId traceId, string format, params object[] arguments) + { + WriteEvent(TraceEventType.Warning, traceId, format, arguments); + } + + public override void WriteError(CompositionTraceId traceId, string format, params object[] arguments) + { + WriteEvent(TraceEventType.Error, traceId, format, arguments); + } + + private static void WriteEvent(TraceEventType eventType, CompositionTraceId traceId, string format, params object[] arguments) + { + if (!Debugger.IsLogging()) + { + return; + } + + string logMessage = CreateLogMessage(eventType, traceId, format, arguments); + Debugger.Log(0, null, logMessage); + } + + internal static string CreateLogMessage(TraceEventType eventType, CompositionTraceId traceId, string format, params object[] arguments) + { + StringBuilder messageBuilder = new StringBuilder(); + + // Format taken from TraceListener.TraceEvent in full framework + messageBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0} {1}: {2} : ", + SourceName, eventType.ToString(), (int)traceId); + + if (arguments == null) + { + messageBuilder.Append(format); + } + else + { + messageBuilder.AppendFormat(CultureInfo.InvariantCulture, format, arguments); + } + + messageBuilder.AppendLine(); + + return messageBuilder.ToString(); + } + + // Copied from TraceEventType in full framework + internal enum TraceEventType + { + Error = 2, + Warning = 4, + Information = 8, + } + } +} + +#endif //!FEATURE_TRACING
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/TraceSourceTraceWriter.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/TraceSourceTraceWriter.cs new file mode 100644 index 00000000000..7cb11adcb6c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/TraceSourceTraceWriter.cs @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +#if FEATURE_TRACING + +using System; +using System.Diagnostics; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Diagnostics +{ + // Represents a trace writer that writes to a System.Diagnostics TraceSource + internal sealed class TraceSourceTraceWriter : TraceWriter + { + internal static readonly TraceSource Source = new TraceSource("System.ComponentModel.Composition", SourceLevels.Warning); + + public override bool CanWriteInformation + { + get { return Source.Switch.ShouldTrace(TraceEventType.Information); } + } + + public override bool CanWriteWarning + { + get { return Source.Switch.ShouldTrace(TraceEventType.Warning); } + } + + public override bool CanWriteError + { + get { return Source.Switch.ShouldTrace(TraceEventType.Error); } + } + + public override void WriteInformation(CompositionTraceId traceId, string format, params object[] arguments) + { + WriteEvent(TraceEventType.Information, traceId, format, arguments); + } + + public override void WriteWarning(CompositionTraceId traceId, string format, params object[] arguments) + { + WriteEvent(TraceEventType.Warning, traceId, format, arguments); + } + + public override void WriteError(CompositionTraceId traceId, string format, params object[] arguments) + { + WriteEvent(TraceEventType.Error, traceId, format, arguments); + } + + private static void WriteEvent(TraceEventType eventType, CompositionTraceId traceId, string format, params object[] arguments) + { + Source.TraceEvent(eventType, (int)traceId, format, arguments); + } + } +} + +#endif //FEATURE_TRACING
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/TraceWriter.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/TraceWriter.cs new file mode 100644 index 00000000000..4be992a2784 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Diagnostics/TraceWriter.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- + +using System; + +namespace System.ComponentModel.Composition.Diagnostics +{ + internal abstract class TraceWriter + { + public abstract bool CanWriteInformation + { + get; + } + + public abstract bool CanWriteWarning + { + get; + } + + public abstract bool CanWriteError + { + get; + } + + public abstract void WriteInformation(CompositionTraceId traceId, string format, params object[] arguments); + + public abstract void WriteWarning(CompositionTraceId traceId, string format, params object[] arguments); + + public abstract void WriteError(CompositionTraceId traceId, string format, params object[] arguments); + } +} + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ErrorBuilder.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ErrorBuilder.cs new file mode 100644 index 00000000000..83eb9d6e71a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ErrorBuilder.cs @@ -0,0 +1,102 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal static class ErrorBuilder + { + public static CompositionError PreventedByExistingImport(ComposablePart part, ImportDefinition import) + { + return CompositionError.Create( + CompositionErrorId.ImportEngine_PreventedByExistingImport, + Strings.ImportEngine_PreventedByExistingImport, + import.ToElement().DisplayName, + part.ToElement().DisplayName); + } + + public static CompositionError InvalidStateForRecompposition(ComposablePart part) + { + return CompositionError.Create( + CompositionErrorId.ImportEngine_InvalidStateForRecomposition, + Strings.ImportEngine_InvalidStateForRecomposition, + part.ToElement().DisplayName); + } + + public static CompositionError ComposeTookTooManyIterations(int maximumNumberOfCompositionIterations) + { + return CompositionError.Create( + CompositionErrorId.ImportEngine_ComposeTookTooManyIterations, + Strings.ImportEngine_ComposeTookTooManyIterations, + maximumNumberOfCompositionIterations); + } + + public static CompositionError CreateImportCardinalityMismatch(ImportCardinalityMismatchException exception, ImportDefinition definition) + { + Assumes.NotNull(exception, definition); + + return CompositionError.Create( + CompositionErrorId.ImportEngine_ImportCardinalityMismatch, + exception.Message, + definition.ToElement(), + (Exception)null); + } + + public static CompositionError CreatePartCannotActivate(ComposablePart part, Exception innerException) + { + Assumes.NotNull(part, innerException); + + ICompositionElement element = part.ToElement(); + return CompositionError.Create( + CompositionErrorId.ImportEngine_PartCannotActivate, + element, + innerException, + Strings.ImportEngine_PartCannotActivate, + element.DisplayName); + } + + public static CompositionError CreatePartCannotSetImport(ComposablePart part, ImportDefinition definition, Exception innerException) + { + Assumes.NotNull(part, definition, innerException); + + ICompositionElement element = definition.ToElement(); + return CompositionError.Create( + CompositionErrorId.ImportEngine_PartCannotSetImport, + element, + innerException, + Strings.ImportEngine_PartCannotSetImport, + element.DisplayName, + part.ToElement().DisplayName); + } + + public static CompositionError CreateCannotGetExportedValue(ComposablePart part, ExportDefinition definition, Exception innerException) + { + Assumes.NotNull(part, definition, innerException); + + ICompositionElement element = definition.ToElement(); + return CompositionError.Create( + CompositionErrorId.ImportEngine_PartCannotGetExportedValue, + element, + innerException, + Strings.ImportEngine_PartCannotGetExportedValue, + element.DisplayName, + part.ToElement().DisplayName); + } + + public static CompositionError CreatePartCycle(ComposablePart part) + { + Assumes.NotNull(part); + + ICompositionElement element = part.ToElement(); + return CompositionError.Create( + CompositionErrorId.ImportEngine_PartCycle, + element, + Strings.ImportEngine_PartCycle, + element.DisplayName); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExceptionBuilder.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExceptionBuilder.cs new file mode 100644 index 00000000000..98b53263fd7 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExceptionBuilder.cs @@ -0,0 +1,95 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal static class ExceptionBuilder + { + public static Exception CreateDiscoveryException(string messageFormat, params string[] arguments) + { + // DiscoveryError (Dev10:602872): This should go through the discovery error reporting when + // we add a way to report discovery errors properly. + return new InvalidOperationException(Format(messageFormat, arguments)); + } + + public static ArgumentException CreateContainsNullElement(string parameterName) + { + Assumes.NotNull(parameterName); + + string message = Format(Strings.Argument_NullElement, parameterName); + + return new ArgumentException(message, parameterName); + } + + public static ObjectDisposedException CreateObjectDisposed(object instance) + { + Assumes.NotNull(instance); + + return new ObjectDisposedException(instance.GetType().ToString()); + } + + public static NotImplementedException CreateNotOverriddenByDerived(string memberName) + { + Assumes.NotNullOrEmpty(memberName); + + string message = Format(Strings.NotImplemented_NotOverriddenByDerived, memberName); + + return new NotImplementedException(message); + } + + public static ArgumentException CreateExportDefinitionNotOnThisComposablePart(string parameterName) + { + Assumes.NotNullOrEmpty(parameterName); + + string message = Format(Strings.ExportDefinitionNotOnThisComposablePart, parameterName); + + return new ArgumentException(message, parameterName); + } + + public static ArgumentException CreateImportDefinitionNotOnThisComposablePart(string parameterName) + { + Assumes.NotNullOrEmpty(parameterName); + + string message = Format(Strings.ImportDefinitionNotOnThisComposablePart, parameterName); + + return new ArgumentException(message, parameterName); + } + + public static CompositionException CreateCannotGetExportedValue(ComposablePart part, ExportDefinition definition, Exception innerException) + { + Assumes.NotNull(part, definition, innerException); + + return new CompositionException( + ErrorBuilder.CreateCannotGetExportedValue(part, definition, innerException)); + } + + public static ArgumentException CreateReflectionModelInvalidPartDefinition(string parameterName, Type partDefinitionType) + { + Assumes.NotNullOrEmpty(parameterName); + Assumes.NotNull(partDefinitionType); + + return new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidPartDefinition, partDefinitionType), parameterName); + } + + public static ArgumentException ExportFactory_TooManyGenericParameters(string typeName) + { + Assumes.NotNullOrEmpty(typeName); + + string message = Format(Strings.ExportFactory_TooManyGenericParameters, typeName); + + return new ArgumentException(message, typeName); + } + + private static string Format(string format, params string[] arguments) + { + return String.Format(CultureInfo.CurrentCulture, format, arguments); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportAttribute.cs new file mode 100644 index 00000000000..ccd88134d8a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportAttribute.cs @@ -0,0 +1,144 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.Diagnostics.CodeAnalysis; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that a type, property, field, or method provides a particular export. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes")] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, + AllowMultiple = true, Inherited = false)] + public class ExportAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type or member marked with this attribute under the default contract name. + /// </summary> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the type of the + /// property or field, or the type itself, that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ExportAttribute() + : this((string)null, (Type)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type or member marked with this attribute under a contract name derived from the + /// specified type. + /// </summary> + /// <param name="contractType"> + /// A <see cref="Type"/> of which to derive the contract name to export the type or + /// member marked with this attribute, under; or <see langword="null"/> to use the + /// default contract name. + /// </param> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on + /// <paramref name="contractType"/>. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the type of the + /// property or field, or the type itself, that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ExportAttribute(Type contractType) + : this((string)null, contractType) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type or member marked with this attribute under the specified contract name. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name to export the type or member + /// marked with this attribute, under; or <see langword="null"/> or an empty string + /// ("") to use the default contract name. + /// </param> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property or field + /// type, or the type itself that this is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ExportAttribute(string contractName) + : this(contractName, (Type)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type or member marked with this attribute under the specified contract name. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name to export the type or member + /// marked with this attribute, under; or <see langword="null"/> or an empty string + /// ("") to use the default contract name. + /// </param> + /// <param name="contractType"> + /// A <see cref="Type"/> of which to derive the contract name to export the type or + /// member marked with this attribute, under; or <see langword="null"/> to use the + /// default contract name. + /// </param> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property or field + /// type, or the type itself that this is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ExportAttribute(string contractName, Type contractType) + { + this.ContractName = contractName; + this.ContractType = contractType; + } + + /// <summary> + /// Gets the contract name to export the type or member under. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the contract name to export the type or member + /// marked with this attribute, under. The default value is an empty string (""). + /// </value> + public string ContractName { get; private set; } + + /// <summary> + /// Get the contract type that is exported by the member that this attribute is attached to. + /// </summary> + /// <value> + /// A <see cref="Type"/> of the export that is be provided. The default value is + /// <see langword="null"/> which means that the type will be obtained by looking at the type on + /// the member that this export is attached to. + /// </value> + public Type ContractType { get; private set; } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportCardinalityCheckResult.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportCardinalityCheckResult.cs new file mode 100644 index 00000000000..566726cbbcd --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportCardinalityCheckResult.cs @@ -0,0 +1,14 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition +{ + internal enum ExportCardinalityCheckResult : int + { + Match, + NoExports, + TooManyExports + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportFactoryOfT.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportFactoryOfT.cs new file mode 100644 index 00000000000..8d72c5df760 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportFactoryOfT.cs @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using Microsoft.Internal; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + public class ExportFactory<T> + { + private Func<Tuple<T, Action>> _exportLifetimeContextCreator; + + public ExportFactory(Func<Tuple<T, Action>> exportLifetimeContextCreator) + { + if (exportLifetimeContextCreator == null) + { + throw new ArgumentNullException("exportLifetimeContextCreator"); + } + + this._exportLifetimeContextCreator = exportLifetimeContextCreator; + } + + public ExportLifetimeContext<T> CreateExport() + { + Tuple<T, Action> untypedLifetimeContext = this._exportLifetimeContextCreator.Invoke(); + return new ExportLifetimeContext<T>(untypedLifetimeContext.Item1, untypedLifetimeContext.Item2); + } + + internal bool IncludeInScopedCatalog(ComposablePartDefinition composablePartDefinition) + { + return this.OnFilterScopedCatalog(composablePartDefinition); + } + + protected virtual bool OnFilterScopedCatalog(ComposablePartDefinition composablePartDefinition) + { + return true; + } + + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportFactoryOfTTMetadata.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportFactoryOfTTMetadata.cs new file mode 100644 index 00000000000..4569a3d5198 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportFactoryOfTTMetadata.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + public class ExportFactory<T, TMetadata> : ExportFactory<T> + { + private readonly TMetadata _metadata; + + public ExportFactory(Func<Tuple<T, Action>> exportLifetimeContextCreator, TMetadata metadata) + : base(exportLifetimeContextCreator) + { + this._metadata = metadata; + } + + public TMetadata Metadata + { + get { return this._metadata; } + } + } +} + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportLifetimeContextOfT.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportLifetimeContextOfT.cs new file mode 100644 index 00000000000..ba239328a61 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportLifetimeContextOfT.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; +using System.Linq; + +namespace System.ComponentModel.Composition +{ + public sealed class ExportLifetimeContext<T> : IDisposable + { + private readonly T _value; + private readonly Action _disposeAction; + + public ExportLifetimeContext(T value, Action disposeAction) + { + this._value = value; + this._disposeAction = disposeAction; + } + + public T Value + { + get + { + return this._value; + } + } + + public void Dispose() + { + if (this._disposeAction != null) + { + this._disposeAction.Invoke(); + } + } + } +} + diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportMetadataAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportMetadataAttribute.cs new file mode 100644 index 00000000000..1663690eae9 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportMetadataAttribute.cs @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies metadata for a type, property, field, or method marked with the + /// <see cref="ExportAttribute"/>. + /// </summary> + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field, + AllowMultiple = true, Inherited = false)] + public sealed class ExportMetadataAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="ExportMetadataAttribute"/> with the + /// specified name and metadata value. + /// </summary> + /// <param name="name"> + /// A <see cref="String"/> containing the name of the metadata value; or + /// <see langword="null"/> to set the <see cref="Name"/> property to an empty + /// string (""). + /// </param> + /// <param name="value"> + /// An <see cref="object"/> containing the metadata value. This can be + /// <see langword="null"/>. + /// </param> + public ExportMetadataAttribute(string name, object value) + { + this.Name = name ?? string.Empty; + this.Value = value; + } + + /// <summary> + /// Gets the name of the metadata value. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the name of the metadata value. + /// </value> + public string Name + { + get; + private set; + } + + /// <summary> + /// Gets the metadata value. + /// </summary> + /// <value> + /// An <see cref="object"/> containing the metadata value. + /// </value> + public object Value + { + get; + private set; + } + + public bool IsMultiple + { + get; + set; + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportServices.DisposableLazy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportServices.DisposableLazy.cs new file mode 100644 index 00000000000..ddf280e8cfe --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportServices.DisposableLazy.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; +using System.Globalization; +using Microsoft.Internal; +using System.Threading; +using System.Collections.Generic; + +namespace System.ComponentModel.Composition +{ + partial class ExportServices + { + private sealed class DisposableLazy<T, TMetadataView> : Lazy<T, TMetadataView>, IDisposable + { + private IDisposable _disposable; + + public DisposableLazy(Func<T> valueFactory, TMetadataView metadataView, IDisposable disposable, LazyThreadSafetyMode mode) + : base(valueFactory, metadataView, mode) + { + Assumes.NotNull(disposable); + + this._disposable = disposable; + } + + void IDisposable.Dispose() + { + this._disposable.Dispose(); + } + } + + private sealed class DisposableLazy<T> : Lazy<T>, IDisposable + { + private IDisposable _disposable; + + public DisposableLazy(Func<T> valueFactory, IDisposable disposable, LazyThreadSafetyMode mode) + : base(valueFactory, mode) + { + Assumes.NotNull(disposable); + + this._disposable = disposable; + } + + void IDisposable.Dispose() + { + this._disposable.Dispose(); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportServices.cs new file mode 100644 index 00000000000..2d093d28828 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ExportServices.cs @@ -0,0 +1,189 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition +{ + // Provides helpers for creating and dealing with Exports + internal static partial class ExportServices + { + private static readonly MethodInfo _createStronglyTypedLazyOfTM = typeof(ExportServices).GetMethod("CreateStronglyTypedLazyOfTM", BindingFlags.NonPublic | BindingFlags.Static); + private static readonly MethodInfo _createStronglyTypedLazyOfT = typeof(ExportServices).GetMethod("CreateStronglyTypedLazyOfT", BindingFlags.NonPublic | BindingFlags.Static); + private static readonly MethodInfo _createSemiStronglyTypedLazy = typeof(ExportServices).GetMethod("CreateSemiStronglyTypedLazy", BindingFlags.NonPublic | BindingFlags.Static); + + internal static readonly Type DefaultMetadataViewType = typeof(IDictionary<string, object>); + internal static readonly Type DefaultExportedValueType = typeof(object); + + internal static bool IsDefaultMetadataViewType(Type metadataViewType) + { + Assumes.NotNull(metadataViewType); + + // Consider all types that IDictionary<string, object> derives from, such + // as ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>> + // and IEnumerable, as default metadata view + return metadataViewType.IsAssignableFrom(DefaultMetadataViewType); + } + + internal static bool IsDictionaryConstructorViewType(Type metadataViewType) + { + Assumes.NotNull(metadataViewType); + + // Does the view type have a constructor that is a Dictionary<string, object> + return metadataViewType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + Type.DefaultBinder, + new Type[] { typeof(IDictionary<string, object>) }, + new ParameterModifier[0]) != null; + } + + internal static Func<Export, object> CreateStronglyTypedLazyFactory(Type exportType, Type metadataViewType) + { + MethodInfo genericMethod = null; + if (metadataViewType != null) + { + genericMethod = _createStronglyTypedLazyOfTM.MakeGenericMethod(exportType ?? ExportServices.DefaultExportedValueType, metadataViewType); + } + else + { + genericMethod = _createStronglyTypedLazyOfT.MakeGenericMethod(exportType ?? ExportServices.DefaultExportedValueType); + } + Assumes.NotNull(genericMethod); + return (Func<Export, object>)Delegate.CreateDelegate(typeof(Func<Export, object>), genericMethod); + } + + internal static Func<Export, Lazy<object, object>> CreateSemiStronglyTypedLazyFactory(Type exportType, Type metadataViewType) + { + MethodInfo genericMethod = _createSemiStronglyTypedLazy.MakeGenericMethod( + exportType ?? ExportServices.DefaultExportedValueType, + metadataViewType ?? ExportServices.DefaultMetadataViewType); + Assumes.NotNull(genericMethod); + return (Func<Export, Lazy<object, object>>)Delegate.CreateDelegate(typeof(Func<Export, Lazy<object,object>>), genericMethod); + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + internal static Lazy<T, M> CreateStronglyTypedLazyOfTM<T, M>(Export export) + { + IDisposable disposable = export as IDisposable; + if (disposable != null) + { + return new DisposableLazy<T, M>( + () => ExportServices.GetCastedExportedValue<T>(export), + AttributedModelServices.GetMetadataView<M>(export.Metadata), + disposable, + LazyThreadSafetyMode.PublicationOnly); + } + else + { + return new Lazy<T, M>( + () => ExportServices.GetCastedExportedValue<T>(export), + AttributedModelServices.GetMetadataView<M>(export.Metadata), + LazyThreadSafetyMode.PublicationOnly); + } + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + internal static Lazy<T> CreateStronglyTypedLazyOfT<T>(Export export) + { + IDisposable disposable = export as IDisposable; + if (disposable != null) + { + return new DisposableLazy<T>( + () => ExportServices.GetCastedExportedValue<T>(export), + disposable, + LazyThreadSafetyMode.PublicationOnly); + } + else + { + return new Lazy<T>(() => ExportServices.GetCastedExportedValue<T>(export), LazyThreadSafetyMode.PublicationOnly); + + } + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + internal static Lazy<object, object> CreateSemiStronglyTypedLazy<T, M>(Export export) + { + IDisposable disposable = export as IDisposable; + if (disposable != null) + { + return new DisposableLazy<object, object>( + () => ExportServices.GetCastedExportedValue<T>(export), + AttributedModelServices.GetMetadataView<M>(export.Metadata), + disposable, + LazyThreadSafetyMode.PublicationOnly); + } + else + { + return new Lazy<object, object>( + () => ExportServices.GetCastedExportedValue<T>(export), + AttributedModelServices.GetMetadataView<M>(export.Metadata), + LazyThreadSafetyMode.PublicationOnly); + } + } + + internal static T GetCastedExportedValue<T>(Export export) + { + return CastExportedValue<T>(export.ToElement(), export.Value); + } + + internal static T CastExportedValue<T>(ICompositionElement element, object exportedValue) + { + object typedExportedValue = null; + + bool succeeded = ContractServices.TryCast(typeof(T), exportedValue, out typedExportedValue); + if (!succeeded) + { + throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, + Strings.ContractMismatch_ExportedValueCannotBeCastToT, + element.DisplayName, + typeof(T))); + } + + return (T)typedExportedValue; + } + + internal static ExportCardinalityCheckResult CheckCardinality<T>(ImportDefinition definition, IEnumerable<T> enumerable) + { + EnumerableCardinality actualCardinality = (enumerable != null) ? enumerable.GetCardinality() : EnumerableCardinality.Zero; + + return MatchCardinality(actualCardinality, definition.Cardinality); + } + + + private static ExportCardinalityCheckResult MatchCardinality(EnumerableCardinality actualCardinality, ImportCardinality importCardinality) + { + switch (actualCardinality) + { + case EnumerableCardinality.Zero: + if (importCardinality == ImportCardinality.ExactlyOne) + { + return ExportCardinalityCheckResult.NoExports; + } + break; + + case EnumerableCardinality.TwoOrMore: + if (importCardinality.IsAtMostOne()) + { + return ExportCardinalityCheckResult.TooManyExports; + } + break; + + default: + Assumes.IsTrue(actualCardinality == EnumerableCardinality.One); + break; + + } + + return ExportCardinalityCheckResult.Match; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AggregateCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AggregateCatalog.cs new file mode 100644 index 00000000000..2772e9b1ecc --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AggregateCatalog.cs @@ -0,0 +1,220 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// A mutable collection of <see cref="ComposablePartCatalog"/>s. + /// </summary> + /// <remarks> + /// This type is thread safe. + /// </remarks> + public class AggregateCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged + { + private ComposablePartCatalogCollection _catalogs = null; + private volatile int _isDisposed = 0; + + /// <summary> + /// Initializes a new instance of the <see cref="AggregateCatalog"/> class. + /// </summary> + public AggregateCatalog() + : this((IEnumerable<ComposablePartCatalog>)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="AggregateCatalog"/> class + /// with the specified catalogs. + /// </summary> + /// <param name="catalogs"> + /// An <see cref="Array"/> of <see cref="ComposablePartCatalog"/> objects to add to the + /// <see cref="AggregateCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="catalogs"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="catalogs"/> contains an element that is <see langword="null"/>. + /// </exception> + public AggregateCatalog(params ComposablePartCatalog[] catalogs) + : this((IEnumerable<ComposablePartCatalog>)catalogs) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="AggregateCatalog"/> class + /// with the specified catalogs. + /// </summary> + /// <param name="catalogs"> + /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartCatalog"/> objects to add + /// to the <see cref="AggregateCatalog"/>; or <see langword="null"/> to + /// create an <see cref="AggregateCatalog"/> that is empty. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="catalogs"/> contains an element that is <see langword="null"/>. + /// </exception> + public AggregateCatalog(IEnumerable<ComposablePartCatalog> catalogs) + { + Requires.NullOrNotNullElements(catalogs, "catalogs"); + + this._catalogs = new ComposablePartCatalogCollection(catalogs, this.OnChanged, this.OnChanging); + } + + /// <summary> + /// Notify when the contents of the Catalog has changed. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed + { + add + { + this._catalogs.Changed += value; + } + remove + { + this._catalogs.Changed -= value; + } + } + + /// <summary> + /// Notify when the contents of the Catalog has changing. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing + { + add + { + this._catalogs.Changing += value; + } + remove + { + this._catalogs.Changing -= value; + } + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="AggregateCatalog"/> has been disposed of. + /// </exception> + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + this.ThrowIfDisposed(); + + Requires.NotNull(definition, "definition"); + + // delegate the query to each catalog and merge the results. + var exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); + foreach (var catalog in this._catalogs) + { + foreach (var export in catalog.GetExports(definition)) + { + exports.Add(export); + } + } + return exports; + } + + /// <summary> + /// Gets the underlying catalogs of the catalog. + /// </summary> + /// <value> + /// An <see cref="ICollection{T}"/> of underlying <see cref="ComposablePartCatalog"/> objects + /// of the <see cref="AggregateCatalog"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="AggregateCatalog"/> has been disposed of. + /// </exception> + public ICollection<ComposablePartCatalog> Catalogs + { + get + { + this.ThrowIfDisposed(); + Contract.Ensures(Contract.Result<ICollection<ComposablePartCatalog>>() != null); + + return this._catalogs; + } + } + + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. +#pragma warning disable 420 + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) +#pragma warning restore 420 + { + this._catalogs.Dispose(); + } + } + } + finally + { + base.Dispose(disposing); + } + } + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + return this._catalogs.SelectMany(catalog => catalog).GetEnumerator(); + } + + /// <summary> + /// Raises the <see cref="INotifyComposablePartCatalogChanged.Changed"/> event. + /// </summary> + /// <param name="e"> + /// An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event. + /// </param> + protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e) + { + this._catalogs.OnChanged(this, e); + } + + /// <summary> + /// Raises the <see cref="INotifyComposablePartCatalogChanged.Changing"/> event. + /// </summary> + /// <param name="e"> + /// An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event. + /// </param> + protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e) + { + this._catalogs.OnChanging(this, e); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed == 1) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AggregateExportProvider.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AggregateExportProvider.cs new file mode 100644 index 00000000000..1a12153514b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AggregateExportProvider.cs @@ -0,0 +1,235 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Threading; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public class AggregateExportProvider : ExportProvider , IDisposable + { + private readonly ReadOnlyCollection<ExportProvider> _readOnlyProviders; + private readonly ExportProvider[] _providers; + private volatile int _isDisposed = 0; + + /// <summary> + /// Initializes a new instance of the <see cref="AggregateExportProvider"/> class. + /// </summary> + /// <param name="providers">The prioritized list of export providers.</param> + /// <exception cref="ArgumentException"> + /// <paramref name="providers"/> contains an element that is <see langword="null"/>. + /// </exception> + /// <remarks> + /// <para> + /// The <see cref="AggregateExportProvider"/> will consult the providers in the order they have been specfied when + /// executing <see cref="ExportProvider.GetExports(ImportDefinition,AtomicComposition)"/>. + /// </para> + /// <para> + /// The <see cref="AggregateExportProvider"/> does not take ownership of the specified providers. + /// That is, it will not try to dispose of any of them when it gets disposed. + /// </para> + /// </remarks> + public AggregateExportProvider(params ExportProvider[] providers) + { + // NOTE : we optimize for the array case here, because the collection of providers is typically tiny + // Arrays are much more compact to store and much faster to create and enumerate + ExportProvider[] copiedProviders = null; + if (providers != null) + { + copiedProviders = new ExportProvider[providers.Length]; + for (int i = 0; i < providers.Length; i++) + { + ExportProvider provider = providers[i]; + if (provider == null) + { + throw ExceptionBuilder.CreateContainsNullElement("providers"); + } + + copiedProviders[i] = provider; + + provider.ExportsChanged += this.OnExportChangedInternal; + provider.ExportsChanging += this.OnExportChangingInternal; + } + } + else + { + copiedProviders = new ExportProvider[] { }; + } + + this._providers = copiedProviders; + this._readOnlyProviders = new ReadOnlyCollection<ExportProvider>(this._providers); + } + + /// <summary> + /// Initializes a new instance of the <see cref="AggregateExportProvider"/> class. + /// </summary> + /// <param name="providers">The prioritized list of export providers. The providers are consulted in order in which they are supplied.</param> + /// <remarks> + /// <para> + /// The <see cref="AggregateExportProvider"/> will consult the providers in the order they have been specfied when + /// executing <see cref="ExportProvider.GetExports(ImportDefinition,AtomicComposition)"/>. + /// </para> + /// <para> + /// The <see cref="AggregateExportProvider"/> does not take ownership of the specified providers. + /// That is, it will not try to dispose of any of them when it gets disposed. + /// </para> + /// </remarks> + public AggregateExportProvider(IEnumerable<ExportProvider> providers) + : this((providers!= null) ? providers.AsArray() : null) + { + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. +#pragma warning disable 420 + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) +#pragma warning restore 420 + { + foreach (ExportProvider provider in this._providers) + { + provider.ExportsChanged -= this.OnExportChangedInternal; + provider.ExportsChanging -= this.OnExportChangingInternal; + } + } + } + } + + /// <summary> + /// Gets the export providers which the aggregate export provider aggregates. + /// </summary> + /// <value> + /// A <see cref="ReadOnlyCollection{T}"/> of <see cref="ExportProvider"/> objects + /// which the <see cref="AggregateExportProvider"/> aggregates. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="AggregateExportProvider"/> has been disposed of. + /// </exception> + public ReadOnlyCollection<ExportProvider> Providers + { + get + { + this.ThrowIfDisposed(); + Contract.Ensures(Contract.Result<ReadOnlyCollection<ExportProvider>>() != null); + + return this._readOnlyProviders; + } + } + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> to get.</param> + /// <returns></returns> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <remarks> + /// <note type="inheritinfo"> + /// The implementers should not treat the cardinality-related mismatches as errors, and are not + /// expected to throw exceptions in those cases. + /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, + /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. + /// </note> + /// </remarks> + protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + + if (definition.Cardinality == ImportCardinality.ZeroOrMore) + { + var exports = new List<Export>(); + foreach (var provider in this._providers) + { + foreach (var export in provider.GetExports(definition, atomicComposition)) + { + exports.Add(export); + } + } + return exports; + } + else + { + IEnumerable<Export> allExports = null; + + // if asked for "one or less", the prioriry is at play - the first provider that agrees to return the value + // which best complies with the request, wins. + foreach (ExportProvider provider in this._providers) + { + IEnumerable<Export> exports; + bool cardinalityCheckResult = provider.TryGetExports(definition, atomicComposition, out exports); + bool anyExports = exports.FastAny(); + if (cardinalityCheckResult && anyExports) + { + // NOTE : if the provider returned nothing, we need to proceed, even if it indicated that the + // cardinality is correct - when asked for "one or less", the provider might - correctly - + // return an empty sequence, but we shouldn't be satisfied with that as providers down the list + // might have a value we are interested in. + return exports; + } + else + { + // TODO + // This is a sneaky thing that we do - if in the end no provider returns the exports with the right cardinality + // we simply return the aggregation of all exports they have returned. This way the end result is still not what we want + // but no information is lost. + // WE SHOULD fix this behavior, but this is ONLY possible if we can treat many exports as no exports for the sake of singles + if (anyExports) + { + allExports = (allExports != null) ? allExports.Concat(exports) : exports; + } + } + } + + return allExports; + } + } + + private void OnExportChangedInternal(object sender, ExportsChangeEventArgs e) + { + this.OnExportsChanged(e); + } + + private void OnExportChangingInternal(object sender, ExportsChangeEventArgs e) + { + this.OnExportsChanging(e); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed == 1) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ApplicationCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ApplicationCatalog.cs new file mode 100644 index 00000000000..f022e2c25d1 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ApplicationCatalog.cs @@ -0,0 +1,232 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Diagnostics; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; +using System.IO; + +namespace System.ComponentModel.Composition.Hosting +{ +#if !MEF_FEATURE_INITIALIZATION + public partial class ApplicationCatalog : ComposablePartCatalog, ICompositionElement + { + private bool _isDisposed = false; + private volatile AggregateCatalog _innerCatalog = null; + private readonly object _thisLock = new object(); + private ICompositionElement _definitionOrigin = null; +#if FEATURE_REFLECTIONCONTEXT + private ReflectionContext _reflectionContext = null; +#endif + + public ApplicationCatalog() {} + + public ApplicationCatalog(ICompositionElement definitionOrigin) + { + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + this._definitionOrigin = definitionOrigin; + } + +#if FEATURE_REFLECTIONCONTEXT + public ApplicationCatalog(ReflectionContext reflectionContext) + { + Requires.NotNull(reflectionContext, "reflectionContext"); + + this._reflectionContext = reflectionContext; + } + + public ApplicationCatalog(ReflectionContext reflectionContext, ICompositionElement definitionOrigin) + { + Requires.NotNull(reflectionContext, "reflectionContext"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + this._reflectionContext = reflectionContext; + this._definitionOrigin = definitionOrigin; + } +#endif + + internal ComposablePartCatalog CreateCatalog(string location, string pattern) + { +#if FEATURE_REFLECTIONCONTEXT + if(this._reflectionContext != null) + { + return (this._definitionOrigin != null) + ? new DirectoryCatalog(location, pattern, this._reflectionContext, this._definitionOrigin) + : new DirectoryCatalog(location, pattern, this._reflectionContext); + } +#endif + return (this._definitionOrigin != null) + ? new DirectoryCatalog(location, pattern, this._definitionOrigin) + : new DirectoryCatalog(location, pattern); + } + +// Note: +// Creating a catalog does not cause change notifications to propagate, For some reason the DeploymentCatalog did, but that is a bug. +// InnerCatalog is delay evaluated, from data supplied at construction time and so does not propagate change notifications + private AggregateCatalog InnerCatalog + { + get + { + if(this._innerCatalog == null) + { + lock(this._thisLock) + { + if(this._innerCatalog == null) + { + var location = AppDomain.CurrentDomain.BaseDirectory; + Assumes.NotNull(location); + + var catalogs = new List<ComposablePartCatalog>(); + catalogs.Add(CreateCatalog(location, "*.exe")); + catalogs.Add(CreateCatalog(location, "*.dll")); + + string relativeSearchPath = AppDomain.CurrentDomain.RelativeSearchPath; + if(!string.IsNullOrEmpty(relativeSearchPath)) + { + string[] probingPaths = relativeSearchPath.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries); + foreach(var probingPath in probingPaths) + { + var path = Path.Combine(location, probingPath); + if(Directory.Exists(path)) + { + catalogs.Add(CreateCatalog(path, "*.dll")); + } + } + } + var innerCatalog = new AggregateCatalog(catalogs); + this._innerCatalog = innerCatalog; + } + } + } + + return this._innerCatalog; + } + } + + protected override void Dispose(bool disposing) + { + try + { + if (!this._isDisposed) + { + IDisposable innerCatalog = null; + lock (this._thisLock) + { + innerCatalog = this._innerCatalog as IDisposable; + this._innerCatalog = null; + this._isDisposed = true; + } + if(innerCatalog != null) + { + innerCatalog.Dispose(); + } + } + } + finally + { + base.Dispose(disposing); + } + } + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + this.ThrowIfDisposed(); + + return this.InnerCatalog.GetEnumerator(); + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="DirectoryCatalog"/> has been disposed of. + /// </exception> + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + this.ThrowIfDisposed(); + + Requires.NotNull(definition, "definition"); + + return this.InnerCatalog.GetExports(definition); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + private string GetDisplayName() + { + return string.Format(CultureInfo.CurrentCulture, + "{0} (Path=\"{1}\") (PrivateProbingPath=\"{2}\")", // NOLOC + this.GetType().Name, + AppDomain.CurrentDomain.BaseDirectory, + AppDomain.CurrentDomain.RelativeSearchPath); + } + + /// <summary> + /// Returns a string representation of the directory catalog. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the string representation of the <see cref="DirectoryCatalog"/>. + /// </returns> + public override string ToString() + { + return GetDisplayName(); + } + + /// <summary> + /// Gets the display name of the ApplicationCatalog. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a human-readable display name of the <see cref="ApplicationCatalog"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + /// <summary> + /// Gets the composition element from which the ApplicationCatalog originated. + /// </summary> + /// <value> + /// This property always returns <see langword="null"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + ICompositionElement ICompositionElement.Origin + { + get { return null; } + } + } +#endif //MEF_FEATURE_INITIALIZATION +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs new file mode 100644 index 00000000000..a8d5c624099 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs @@ -0,0 +1,602 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// An immutable ComposablePartCatalog created from a managed code assembly. + /// </summary> + /// <remarks> + /// This type is thread safe. + /// </remarks> + [DebuggerTypeProxy(typeof(AssemblyCatalogDebuggerProxy))] + public class AssemblyCatalog : ComposablePartCatalog, ICompositionElement + { + private readonly object _thisLock = new object(); + private readonly ICompositionElement _definitionOrigin; + private volatile Assembly _assembly = null; + private volatile ComposablePartCatalog _innerCatalog = null; + private int _isDisposed = 0; + +#if FEATURE_REFLECTIONCONTEXT + private ReflectionContext _reflectionContext = default(ReflectionContext); +#endif //FEATURE_REFLECTIONCONTEXT + +#if FEATURE_REFLECTIONFILEIO + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified code base. + /// </summary> + /// <param name="codeBase"> + /// A <see cref="String"/> containing the code base of the assembly containing the + /// attributed <see cref="Type"/> objects to add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="codeBase"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="codeBase"/> is a zero-length string, contains only white space, + /// or contains one or more invalid characters as defined by <see cref="Path.InvalidPathChars"/>. + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified path, file name, or both exceed the system-defined maximum length. + /// </exception> + /// <exception cref="SecurityException"> + /// The caller does not have path discovery permission. + /// </exception> + /// <exception cref="FileNotFoundException"> + /// <paramref name="codeBase"/> is not found. + /// </exception> + /// <exception cref="FileLoadException "> + /// <paramref name="codeBase"/> could not be loaded. + /// <para> + /// -or- + /// </para> + /// <paramref name="codeBase"/> specified a directory. + /// </exception> + /// <exception cref="BadImageFormatException"> + /// <paramref name="codeBase"/> is not a valid assembly + /// -or- + /// Version 2.0 or later of the common language runtime is currently loaded + /// and <paramref name="codeBase"/> was compiled with a later version. + /// </exception> + /// <remarks> + /// The assembly referenced by <paramref langword="codeBase"/> is loaded into the Load context. + /// </remarks> + public AssemblyCatalog(string codeBase) + { + Requires.NotNullOrEmpty(codeBase, "codeBase"); + + InitializeAssemblyCatalog(LoadAssembly(codeBase)); + this._definitionOrigin = this; + } +#endif //FEATURE_REFLECTIONFILEIO + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified code base. + /// </summary> + /// <param name="codeBase"> + /// A <see cref="String"/> containing the code base of the assembly containing the + /// attributed <see cref="Type"/> objects to add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition<see cref="AssemblyCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="codeBase"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="reflectionContext"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="codeBase"/> is a zero-length string, contains only white space, + /// or contains one or more invalid characters as defined by <see cref="Path.InvalidPathChars"/>. + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified path, file name, or both exceed the system-defined maximum length. + /// </exception> + /// <exception cref="SecurityException"> + /// The caller does not have path discovery permission. + /// </exception> + /// <exception cref="FileNotFoundException"> + /// <paramref name="codeBase"/> is not found. + /// </exception> + /// <exception cref="FileLoadException "> + /// <paramref name="codeBase"/> could not be loaded. + /// <para> + /// -or- + /// </para> + /// <paramref name="codeBase"/> specified a directory. + /// </exception> + /// <exception cref="BadImageFormatException"> + /// <paramref name="codeBase"/> is not a valid assembly + /// -or- + /// Version 2.0 or later of the common language runtime is currently loaded + /// and <paramref name="codeBase"/> was compiled with a later version. + /// </exception> + /// <remarks> + /// The assembly referenced by <paramref langword="codeBase"/> is loaded into the Load context. + /// </remarks> + public AssemblyCatalog(string codeBase, ReflectionContext reflectionContext) + { + Requires.NotNullOrEmpty(codeBase, "codeBase"); + Requires.NotNull(reflectionContext, "reflectionContext"); + + InitializeAssemblyCatalog(LoadAssembly(codeBase)); + this._reflectionContext = reflectionContext; + this._definitionOrigin = this; + } +#endif //FEATURE_REFLECTIONCONTEXT + +#if FEATURE_REFLECTIONFILEIO + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified code base. + /// </summary> + /// <param name="codeBase"> + /// A <see cref="String"/> containing the code base of the assembly containing the + /// attributed <see cref="Type"/> objects to add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="codeBase"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="codeBase"/> is a zero-length string, contains only white space, + /// or contains one or more invalid characters as defined by <see cref="Path.InvalidPathChars"/>. + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified path, file name, or both exceed the system-defined maximum length. + /// </exception> + /// <exception cref="SecurityException"> + /// The caller does not have path discovery permission. + /// </exception> + /// <exception cref="FileNotFoundException"> + /// <paramref name="codeBase"/> is not found. + /// </exception> + /// <exception cref="FileLoadException "> + /// <paramref name="codeBase"/> could not be loaded. + /// <para> + /// -or- + /// </para> + /// <paramref name="codeBase"/> specified a directory. + /// </exception> + /// <exception cref="BadImageFormatException"> + /// <paramref name="codeBase"/> is not a valid assembly + /// -or- + /// Version 2.0 or later of the common language runtime is currently loaded + /// and <paramref name="codeBase"/> was compiled with a later version. + /// </exception> + /// <remarks> + /// The assembly referenced by <paramref langword="codeBase"/> is loaded into the Load context. + /// </remarks> + public AssemblyCatalog(string codeBase, ICompositionElement definitionOrigin) + { + Requires.NotNullOrEmpty(codeBase, "codeBase"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + InitializeAssemblyCatalog(LoadAssembly(codeBase)); + this._definitionOrigin = definitionOrigin; + } +#endif //FEATURE_REFLECTIONFILEIO + +#if FEATURE_REFLECTIONFILEIO && FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified code base. + /// </summary> + /// <param name="codeBase"> + /// A <see cref="String"/> containing the code base of the assembly containing the + /// attributed <see cref="Type"/> objects to add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition<see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="codeBase"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="reflectionContext"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="codeBase"/> is a zero-length string, contains only white space, + /// or contains one or more invalid characters as defined by <see cref="Path.InvalidPathChars"/>. + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified path, file name, or both exceed the system-defined maximum length. + /// </exception> + /// <exception cref="SecurityException"> + /// The caller does not have path discovery permission. + /// </exception> + /// <exception cref="FileNotFoundException"> + /// <paramref name="codeBase"/> is not found. + /// </exception> + /// <exception cref="FileLoadException "> + /// <paramref name="codeBase"/> could not be loaded. + /// <para> + /// -or- + /// </para> + /// <paramref name="codeBase"/> specified a directory. + /// </exception> + /// <exception cref="BadImageFormatException"> + /// <paramref name="codeBase"/> is not a valid assembly + /// -or- + /// Version 2.0 or later of the common language runtime is currently loaded + /// and <paramref name="codeBase"/> was compiled with a later version. + /// </exception> + /// <remarks> + /// The assembly referenced by <paramref langword="codeBase"/> is loaded into the Load context. + /// </remarks> + public AssemblyCatalog(string codeBase, ReflectionContext reflectionContext, ICompositionElement definitionOrigin) + { + Requires.NotNullOrEmpty(codeBase, "codeBase"); + Requires.NotNull(reflectionContext, "reflectionContext"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + InitializeAssemblyCatalog(LoadAssembly(codeBase)); + this._reflectionContext = reflectionContext; + this._definitionOrigin = definitionOrigin; + } +#endif //FEATURE_REFLECTIONFILEIO && FEATURE_REFLECTIONCONTEXT + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified assembly and reflection context. + /// </summary> + /// <param name="assembly"> + /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects to + /// add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="assembly"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="assembly"/> was loaded in the reflection-only context. + /// <para> + /// -or- + /// </para> + /// <paramref name="reflectionContext"/> is <see langword="null"/>. + /// </exception> + public AssemblyCatalog(Assembly assembly, ReflectionContext reflectionContext) + { + Requires.NotNull(assembly, "assembly"); + Requires.NotNull(reflectionContext, "reflectionContext"); + + InitializeAssemblyCatalog(assembly); + this._reflectionContext = reflectionContext; + this._definitionOrigin = this; + } + + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified assembly, reflectionContext and definitionOrigin. + /// </summary> + /// <param name="assembly"> + /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects to + /// add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="assembly"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="assembly"/> was loaded in the reflection-only context. + /// <para> + /// -or- + /// </para> + /// <paramref name="reflectionContext"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + public AssemblyCatalog(Assembly assembly, ReflectionContext reflectionContext, ICompositionElement definitionOrigin) + { + Requires.NotNull(assembly, "assembly"); + Requires.NotNull(reflectionContext, "reflectionContext"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + InitializeAssemblyCatalog(assembly); + this._reflectionContext = reflectionContext; + this._definitionOrigin = definitionOrigin; + } +#endif //FEATURE_REFLECTIONCONTEXT + + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified assembly. + /// </summary> + /// <param name="assembly"> + /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects to + /// add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="assembly"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="assembly"/> was loaded in the reflection-only context. + /// </exception> + public AssemblyCatalog(Assembly assembly) + { + Requires.NotNull(assembly, "assembly"); + + InitializeAssemblyCatalog(assembly); + this._definitionOrigin = this; + } + + /// <summary> + /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class + /// with the specified assembly. + /// </summary> + /// <param name="assembly"> + /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects to + /// add to the <see cref="AssemblyCatalog"/>. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="assembly"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="assembly"/> was loaded in the reflection-only context. + /// <para> + /// -or- + /// </para> + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + public AssemblyCatalog(Assembly assembly, ICompositionElement definitionOrigin) + { + Requires.NotNull(assembly, "assembly"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + InitializeAssemblyCatalog(assembly); + this._definitionOrigin = definitionOrigin; + } + + private void InitializeAssemblyCatalog(Assembly assembly) + { +#if FEATURE_REFLECTIONONLY + if (assembly.ReflectionOnly) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_AssemblyReflectionOnly, "assembly"), "assembly"); + } +#endif //FEATURE_REFLECTIONONLY + this._assembly = assembly; + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePartCatalog"/> has been disposed of. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>, if no + /// <see cref="ExportDefinition"/> match the conditions defined by + /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>. + /// </note> + /// </remarks> + [SuppressMessage("Microsoft.Contracts", "CC1055", Justification = "Precondition is being validated in the call to inner catalog")] + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + return this.InnerCatalog.GetExports(definition); + } + + private ComposablePartCatalog InnerCatalog + { + get + { + this.ThrowIfDisposed(); + + if (this._innerCatalog == null) + { +#if FEATURE_REFLECTIONCONTEXT + var catalogReflectionContextAttribute = this._assembly.GetFirstAttribute<CatalogReflectionContextAttribute>(); + var assembly = (catalogReflectionContextAttribute != null) + ? catalogReflectionContextAttribute.CreateReflectionContext().MapAssembly(this._assembly) + : this._assembly; +#else + var assembly = this._assembly; +#endif //FEATURE_REFLECTIONCONTEXT + lock (this._thisLock) + { + if (this._innerCatalog == null) + { +#if FEATURE_REFLECTIONCONTEXT + var catalog = (this._reflectionContext != null) + ? new TypeCatalog(assembly.GetTypes(), this._reflectionContext, this._definitionOrigin) + : new TypeCatalog(assembly.GetTypes(), this._definitionOrigin); +#else + var catalog = new TypeCatalog(assembly.GetTypes(), this._definitionOrigin); +#endif //FEATURE_REFLECTIONCONTEXT + Thread.MemoryBarrier(); + this._innerCatalog = catalog; + } + } + } + return this._innerCatalog; + } + } + + /// <summary> + /// Gets the assembly containing the attributed types contained within the assembly + /// catalog. + /// </summary> + /// <value> + /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects + /// contained within the <see cref="AssemblyCatalog"/>. + /// </value> + public Assembly Assembly + { + get + { + Contract.Ensures(Contract.Result<Assembly>() != null); + + return this._assembly; + } + } + + /// <summary> + /// Gets the display name of the assembly catalog. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a human-readable display name of the <see cref="AssemblyCatalog"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + /// <summary> + /// Gets the composition element from which the assembly catalog originated. + /// </summary> + /// <value> + /// This property always returns <see langword="null"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + ICompositionElement ICompositionElement.Origin + { + get { return null; } + } + + + /// <summary> + /// Returns a string representation of the assembly catalog. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the string representation of the <see cref="AssemblyCatalog"/>. + /// </returns> + public override string ToString() + { + return this.GetDisplayName(); + } + + + protected override void Dispose(bool disposing) + { + try + { + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) + { + if (disposing) + { + if (this._innerCatalog != null) + { + this._innerCatalog.Dispose(); + } + } + } + } + finally + { + base.Dispose(disposing); + } + } + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + return this.InnerCatalog.GetEnumerator(); + } + + private void ThrowIfDisposed() + { + if (this._isDisposed == 1) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + private string GetDisplayName() + { + return string.Format(CultureInfo.CurrentCulture, + "{0} (Assembly=\"{1}\")", // NOLOC + GetType().Name, + this.Assembly.FullName); + } + +#if FEATURE_REFLECTIONFILEIO + private static Assembly LoadAssembly(string codeBase) + { + Requires.NotNullOrEmpty(codeBase, "codeBase"); + + AssemblyName assemblyName; + + try + { + assemblyName = AssemblyName.GetAssemblyName(codeBase); + } + catch (ArgumentException) + { + assemblyName = new AssemblyName(); + assemblyName.CodeBase = codeBase; + } + + return Assembly.Load(assemblyName); + } +#endif //FEATURE_REFLECTIONFILEIO + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalogDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalogDebuggerProxy.cs new file mode 100644 index 00000000000..e8f519852fa --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalogDebuggerProxy.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + internal class AssemblyCatalogDebuggerProxy + { + private readonly AssemblyCatalog _catalog; + + public AssemblyCatalogDebuggerProxy(AssemblyCatalog catalog) + { + Requires.NotNull(catalog, "catalog"); + + this._catalog = catalog; + } + + public Assembly Assembly + { + get { return this._catalog.Assembly; } + } + + public ReadOnlyCollection<ComposablePartDefinition> Parts + { + // NOTE: This shouldn't be cached, so that on every query of + // the current value of the underlying catalog is respected. + // We use ReadOnlyCollection as arrays do not have the + // appropriate debugger display attributes applied to them. + get { return this._catalog.Parts.ToReadOnlyCollection(); } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AtomicComposition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AtomicComposition.cs new file mode 100644 index 00000000000..f0a2fa51c4d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AtomicComposition.cs @@ -0,0 +1,315 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// AtomicComposition provides lightweight atomicCompositional semantics to enable temporary + /// state to be managed for a series of nested atomicCompositions. Each atomicComposition maintains + /// queryable state along with a sequence of actions necessary to complete the state when + /// the atomicComposition is no longer in danger of being rolled back. State is completed or + /// rolled back when the atomicComposition is disposed, depending on the state of the + /// CompleteOnDipose property which defaults to false. The using(...) pattern in C# is a + /// convenient mechanism for defining atomicComposition scopes. + /// + /// The least obvious aspects of AtomicComposition deal with nesting. + /// + /// Firstly, no complete actions are actually performed until the outermost atomicComposition is + /// completed. Completeting or rolling back nested atomicCompositions serves only to change which + /// actions would be completed the outer atomicComposition. + /// + /// Secondly, state is added in the form of queries associated with an object key. The + /// key represents a unique object the state is being held on behalf of. The quieries are + /// accessed throught the Query methods which provide automatic chaining to execute queries + /// across the target atomicComposition and its inner atomicComposition as appropriate. + /// + /// Lastly, when a nested atomicComposition is created for a given outer the outer atomicComposition is locked. + /// It remains locked until the inner atomicComposition is disposed or completeed preventing the addition of + /// state, actions or other inner atomicCompositions. + /// </summary> + public class AtomicComposition : IDisposable + { + private readonly AtomicComposition _outerAtomicComposition; + private KeyValuePair<object, object>[] _values; + private int _valueCount = 0; + private List<Action> _completeActionList; + private List<Action> _revertActionList; + private bool _isDisposed = false; + private bool _isCompleted = false; + private bool _containsInnerAtomicComposition = false; + + public AtomicComposition() + : this(null) + { + } + + public AtomicComposition(AtomicComposition outerAtomicComposition) + { + // Lock the inner atomicComposition so that we can assume nothing changes except on + // the innermost scope, and thereby optimize the query path + if (outerAtomicComposition != null) + { + this._outerAtomicComposition = outerAtomicComposition; + this._outerAtomicComposition.ContainsInnerAtomicComposition = true; + } + } + + public void SetValue(object key, object value) + { + ThrowIfDisposed(); + ThrowIfCompleted(); + ThrowIfContainsInnerAtomicComposition(); + + Requires.NotNull(key, "key"); + + SetValueInternal(key, value); + } + + public bool TryGetValue<T>(object key, out T value) + { + return TryGetValue(key, false, out value); + } + + [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters")] + public bool TryGetValue<T>(object key, bool localAtomicCompositionOnly, out T value) + { + ThrowIfDisposed(); + ThrowIfCompleted(); + + Requires.NotNull(key, "key"); + + return TryGetValueInternal(key, localAtomicCompositionOnly, out value); + } + + public void AddCompleteAction(Action completeAction) + { + ThrowIfDisposed(); + ThrowIfCompleted(); + ThrowIfContainsInnerAtomicComposition(); + + Requires.NotNull(completeAction, "completeAction"); + + if (this._completeActionList == null) + { + this._completeActionList = new List<Action>(); + } + this._completeActionList.Add(completeAction); + } + + public void AddRevertAction(Action revertAction) + { + ThrowIfDisposed(); + ThrowIfCompleted(); + ThrowIfContainsInnerAtomicComposition(); + + Requires.NotNull(revertAction, "revertAction"); + + if (this._revertActionList == null) + { + this._revertActionList = new List<Action>(); + } + this._revertActionList.Add(revertAction); + } + + public void Complete() + { + ThrowIfDisposed(); + ThrowIfCompleted(); + + if (this._outerAtomicComposition == null) + { // Execute all the complete actions + FinalComplete(); + } + else + { // Copy the actions and state to the outer atomicComposition + CopyComplete(); + } + + this._isCompleted = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + ThrowIfDisposed(); + this._isDisposed = true; + + if (this._outerAtomicComposition != null) + { + this._outerAtomicComposition.ContainsInnerAtomicComposition = false; + } + + // Revert is always immediate and involves forgetting information and + // exceuting any appropriate revert actions + if (!this._isCompleted) + { + if (this._revertActionList != null) + { + // Execute the revert actions in reverse order to ensure + // everything incrementally rollsback its state. + for (int i = this._revertActionList.Count - 1; i >= 0; i--) + { + Action action = this._revertActionList[i]; + action(); + } + this._revertActionList = null; + } + } + } + + private void FinalComplete() + { + // Completeting the outer most scope is easy, just execute all the actions + if (this._completeActionList != null) + { + foreach (Action action in this._completeActionList) + { + action(); + } + this._completeActionList = null; + } + } + + private void CopyComplete() + { + Assumes.NotNull(this._outerAtomicComposition); + + this._outerAtomicComposition.ContainsInnerAtomicComposition = false; + + // Inner scopes are much odder, because completeting them means coalescing them into the + // outer scope - the complete or revert actions are deferred until the outermost scope completes + // or any intermediate rolls back + if (this._completeActionList != null) + { + foreach (Action action in this._completeActionList) + { + this._outerAtomicComposition.AddCompleteAction(action); + } + } + + if (this._revertActionList != null) + { + foreach (Action action in this._revertActionList) + { + this._outerAtomicComposition.AddRevertAction(action); + } + } + + // We can copy over existing atomicComposition entries because they're either already chained or + // overwrite by design and can now be completed or rolled back together + for (var index = 0; index < this._valueCount; index++) + { + this._outerAtomicComposition.SetValueInternal( + this._values[index].Key, this._values[index].Value); + } + } + + private bool ContainsInnerAtomicComposition + { + set + { + if (value == true && this._containsInnerAtomicComposition == true) + { + throw new InvalidOperationException(Strings.AtomicComposition_AlreadyNested); + } + this._containsInnerAtomicComposition = value; + } + } + + private bool TryGetValueInternal<T>(object key, bool localAtomicCompositionOnly, out T value) + { + for (var index = 0; index < this._valueCount; index++) + { + if (this._values[index].Key == key) + { + value = (T)this._values[index].Value; + return true; + } + } + + // If there's no atomicComposition available then recurse until we hit the outermost + // scope, where upon we go ahead and return null + if (!localAtomicCompositionOnly && this._outerAtomicComposition != null) + { + return this._outerAtomicComposition.TryGetValueInternal<T>(key, localAtomicCompositionOnly, out value); + } + + value = default(T); + return false; + } + + private void SetValueInternal(object key, object value) + { + // Handle overwrites quickly + for (var index = 0; index < this._valueCount; index++) + { + if (this._values[index].Key == key) + { + this._values[index] = new KeyValuePair<object,object>(key, value); + return; + } + } + + // Expand storage when needed + if (this._values == null || this._valueCount == this._values.Length) + { + var newQueries = new KeyValuePair<object, object>[this._valueCount == 0 ? 5 : this._valueCount * 2]; + if (this._values != null) + { + Array.Copy(this._values, newQueries, this._valueCount); + } + this._values = newQueries; + } + + // Store a new entry + this._values[_valueCount] = new KeyValuePair<object, object>(key, value); + this._valueCount++; + return; + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfContainsInnerAtomicComposition() + { + if (this._containsInnerAtomicComposition) + { + throw new InvalidOperationException(Strings.AtomicComposition_PartOfAnotherAtomicComposition); + } + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfCompleted() + { + if (this._isCompleted) + { + throw new InvalidOperationException(Strings.AtomicComposition_AlreadyCompleted); + } + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AtomicCompositionExtensions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AtomicCompositionExtensions.cs new file mode 100644 index 00000000000..af573295aa7 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/AtomicCompositionExtensions.cs @@ -0,0 +1,56 @@ +using System; +using System.Diagnostics; +using System.Collections.Generic; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + internal static class AtomicCompositionExtensions + { + internal static T GetValueAllowNull<T>(this AtomicComposition atomicComposition, T defaultResultAndKey) where T : class + { + Assumes.NotNull(defaultResultAndKey); + + return GetValueAllowNull<T>(atomicComposition, defaultResultAndKey, defaultResultAndKey); + } + + internal static T GetValueAllowNull<T>(this AtomicComposition atomicComposition, object key, T defaultResult) + { + T result; + if (atomicComposition != null && atomicComposition.TryGetValue(key, out result)) + { + return result; + } + + return defaultResult; + } + + internal static void AddRevertActionAllowNull(this AtomicComposition atomicComposition, Action action) + { + Assumes.NotNull(action); + + if (atomicComposition == null) + { + action(); + } + else + { + atomicComposition.AddRevertAction(action); + } + } + + internal static void AddCompleteActionAllowNull(this AtomicComposition atomicComposition, Action action) + { + Assumes.NotNull(action); + + if (atomicComposition == null) + { + action(); + } + else + { + atomicComposition.AddCompleteAction(action); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.CatalogChangeProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.CatalogChangeProxy.cs new file mode 100644 index 00000000000..56e4f01db94 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.CatalogChangeProxy.cs @@ -0,0 +1,64 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider : ExportProvider, IDisposable + { + private class CatalogChangeProxy : ComposablePartCatalog + { + private ComposablePartCatalog _originalCatalog; + private List<ComposablePartDefinition> _addedParts; + private HashSet<ComposablePartDefinition> _removedParts; + + public CatalogChangeProxy(ComposablePartCatalog originalCatalog, + IEnumerable<ComposablePartDefinition> addedParts, + IEnumerable<ComposablePartDefinition> removedParts) + { + this._originalCatalog = originalCatalog; + this._addedParts = new List<ComposablePartDefinition>(addedParts); + this._removedParts = new HashSet<ComposablePartDefinition>(removedParts); + } + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + return this._originalCatalog.Concat(this._addedParts).Except(this._removedParts).GetEnumerator(); + } + + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports( + ImportDefinition definition) + { + Requires.NotNull(definition, "definition"); + + var originalExports = this._originalCatalog.GetExports(definition); + var trimmedExports = originalExports.Where(partAndExport => + !this._removedParts.Contains(partAndExport.Item1)); + + var addedExports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); + foreach (var part in this._addedParts) + { + foreach (var export in part.ExportDefinitions) + { + if (definition.IsConstraintSatisfiedBy(export)) + { + addedExports.Add(new Tuple<ComposablePartDefinition, ExportDefinition>(part, export)); + } + } + } + return trimmedExports.Concat(addedExports); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.CatalogExport.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.CatalogExport.cs new file mode 100644 index 00000000000..7214b94d0a4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.CatalogExport.cs @@ -0,0 +1,173 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider + { + private class CatalogExport : Export + { + protected readonly CatalogExportProvider _catalogExportProvider; + protected readonly ComposablePartDefinition _partDefinition; + protected readonly ExportDefinition _definition; + + public CatalogExport(CatalogExportProvider catalogExportProvider, + ComposablePartDefinition partDefinition, ExportDefinition definition) + { + this._catalogExportProvider = catalogExportProvider; + this._partDefinition = partDefinition; + this._definition = definition; + } + + public override ExportDefinition Definition + { + get + { + return this._definition; + } + } + + protected virtual bool IsSharedPart + { + get + { + return true; + } + } + + protected CatalogPart GetPartCore() + { + return this._catalogExportProvider.GetComposablePart(this._partDefinition, this.IsSharedPart); + } + + protected void ReleasePartCore(CatalogPart part, object value) + { + this._catalogExportProvider.ReleasePart(value, part, null); + } + + protected virtual CatalogPart GetPart() + { + return this.GetPartCore(); + } + + protected override object GetExportedValueCore() + { + return this._catalogExportProvider.GetExportedValue(this.GetPart(), this._definition, this.IsSharedPart); + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + public static CatalogExport CreateExport(CatalogExportProvider catalogExportProvider, + ComposablePartDefinition partDefinition, ExportDefinition definition, CreationPolicy importCreationPolicy) + { + CreationPolicy partPolicy = partDefinition.Metadata.GetValue<CreationPolicy>(CompositionConstants.PartCreationPolicyMetadataName); + bool isSharedPart = ShouldUseSharedPart(partPolicy, importCreationPolicy); + + if (isSharedPart) + { + return new CatalogExport(catalogExportProvider, partDefinition, definition); + } + else + { + return new NonSharedCatalogExport(catalogExportProvider, partDefinition, definition); + } + } + + private static bool ShouldUseSharedPart(CreationPolicy partPolicy, CreationPolicy importPolicy) + { + // Matrix that details which policy to use for a given part to satisfy a given import. + // Part.Any Part.Shared Part.NonShared + // Import.Any Shared Shared NonShared + // Import.Shared Shared Shared N/A + // Import.NonShared NonShared N/A NonShared + + switch (partPolicy) + { + case CreationPolicy.Any: + { + if (importPolicy == CreationPolicy.Any || + importPolicy == CreationPolicy.NewScope || + importPolicy == CreationPolicy.Shared) + { + return true; + } + return false; + } + + case CreationPolicy.NonShared: + { + Assumes.IsTrue(importPolicy != CreationPolicy.Shared); + return false; + } + + default: + { + Assumes.IsTrue(partPolicy == CreationPolicy.Shared); + Assumes.IsTrue(importPolicy != CreationPolicy.NonShared && importPolicy != CreationPolicy.NewScope); + return true; + } + } + } + } + + private sealed class NonSharedCatalogExport : CatalogExport, IDisposable + { + private CatalogPart _part; + private readonly object _lock = new object(); + + public NonSharedCatalogExport(CatalogExportProvider catalogExportProvider, + ComposablePartDefinition partDefinition, ExportDefinition definition) + : base(catalogExportProvider, partDefinition, definition) + { + } + + protected override CatalogPart GetPart() + { + // we need to ensure that the part gets created only once, as the export contract requires that the same value be returned on subsequent calls + if (this._part == null) + { + CatalogPart part = this.GetPartCore(); + + lock (this._lock) + { + if (this._part == null) + { + Thread.MemoryBarrier(); + this._part = part; + part = null; + } + } + + if (part != null) + { + this.ReleasePartCore(part, null); + } + } + + return this._part; + } + + protected override bool IsSharedPart + { + get + { + return false; + } + } + + void IDisposable.Dispose() + { + if (this._part != null) + { + this.ReleasePartCore(this._part, this.Value); + this._part = null; + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.FactoryExport.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.FactoryExport.cs new file mode 100644 index 00000000000..cf9ea6ef0e5 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.FactoryExport.cs @@ -0,0 +1,143 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider + { + internal abstract class FactoryExport : Export + { + private readonly ComposablePartDefinition _partDefinition; + private readonly ExportDefinition _exportDefinition; + private ExportDefinition _factoryExportDefinition; + private FactoryExportPartDefinition _factoryExportPartDefinition; + + public FactoryExport(ComposablePartDefinition partDefinition, ExportDefinition exportDefinition) + { + this._partDefinition = partDefinition; + this._exportDefinition = exportDefinition; + this._factoryExportDefinition = new PartCreatorExportDefinition(this._exportDefinition); + } + + public override ExportDefinition Definition + { + get { return this._factoryExportDefinition; } + } + + protected override object GetExportedValueCore() + { + if (this._factoryExportPartDefinition == null) + { + this._factoryExportPartDefinition = new FactoryExportPartDefinition(this); + } + return this._factoryExportPartDefinition; + } + + protected ComposablePartDefinition UnderlyingPartDefinition + { + get + { + return this._partDefinition; + } + } + + protected ExportDefinition UnderlyingExportDefinition + { + get + { + return this._exportDefinition; + } + } + + public abstract Export CreateExportProduct(); + + private class FactoryExportPartDefinition : ComposablePartDefinition + { + private readonly FactoryExport _FactoryExport; + + public FactoryExportPartDefinition(FactoryExport FactoryExport) + { + this._FactoryExport = FactoryExport; + } + + public override IEnumerable<ExportDefinition> ExportDefinitions + { + get { return new ExportDefinition[] { this._FactoryExport.Definition }; } + } + + public override IEnumerable<ImportDefinition> ImportDefinitions + { + get { return Enumerable.Empty<ImportDefinition>(); } + } + + public ExportDefinition FactoryExportDefinition + { + get { return this._FactoryExport.Definition; } + } + + public Export CreateProductExport() + { + return this._FactoryExport.CreateExportProduct(); + } + + public override ComposablePart CreatePart() + { + return new FactoryExportPart(this); + } + } + + private sealed class FactoryExportPart : ComposablePart, IDisposable + { + private readonly FactoryExportPartDefinition _definition; + private readonly Export _export; + + public FactoryExportPart(FactoryExportPartDefinition definition) + { + this._definition = definition; + this._export = definition.CreateProductExport(); + } + + public override IEnumerable<ExportDefinition> ExportDefinitions + { + get { return this._definition.ExportDefinitions; } + } + + public override IEnumerable<ImportDefinition> ImportDefinitions + { + get { return this._definition.ImportDefinitions; } + } + + public override object GetExportedValue(ExportDefinition definition) + { + if (definition != this._definition.FactoryExportDefinition) + { + throw ExceptionBuilder.CreateExportDefinitionNotOnThisComposablePart("definition"); + } + + return this._export.Value; + } + + public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports) + { + throw ExceptionBuilder.CreateImportDefinitionNotOnThisComposablePart("definition"); + } + + public void Dispose() + { + IDisposable disposable = this._export as IDisposable; + + if (disposable != null) + { + disposable.Dispose(); + } + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.PartCreatorExport.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.PartCreatorExport.cs new file mode 100644 index 00000000000..1f5e7bd537a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.PartCreatorExport.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider + { + internal class PartCreatorExport : FactoryExport + { + private readonly CatalogExportProvider _catalogExportProvider; + + public PartCreatorExport(CatalogExportProvider catalogExportProvider, ComposablePartDefinition partDefinition, ExportDefinition exportDefinition) : + base(partDefinition, exportDefinition) + { + this._catalogExportProvider = catalogExportProvider; + } + + public override Export CreateExportProduct() + { + return new NonSharedCatalogExport(this._catalogExportProvider, this.UnderlyingPartDefinition, this.UnderlyingExportDefinition); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.ScopeFactoryExport.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.ScopeFactoryExport.cs new file mode 100644 index 00000000000..9267c282066 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.ScopeFactoryExport.cs @@ -0,0 +1,117 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; +using System.Threading; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider + { + internal class ScopeFactoryExport : FactoryExport + { + private readonly ScopeManager _scopeManager; + private readonly CompositionScopeDefinition _catalog; + + internal ScopeFactoryExport(ScopeManager scopeManager, CompositionScopeDefinition catalog, ComposablePartDefinition partDefinition, ExportDefinition exportDefinition) : + base(partDefinition, exportDefinition) + { + this._scopeManager = scopeManager; + this._catalog = catalog; + } + + public virtual Export CreateExportProduct(Func<ComposablePartDefinition, bool> filter) + { + return new ScopeCatalogExport(this, filter); + } + + public override Export CreateExportProduct() + { + return new ScopeCatalogExport(this, null); + } + + private sealed class ScopeCatalogExport : Export, IDisposable + { + private readonly ScopeFactoryExport _scopeFactoryExport; + private Func<ComposablePartDefinition, bool> _catalogFilter; + private CompositionContainer _childContainer; + private Export _export; + private readonly object _lock = new object(); + + public ScopeCatalogExport(ScopeFactoryExport scopeFactoryExport, Func<ComposablePartDefinition, bool> catalogFilter) + { + this._scopeFactoryExport = scopeFactoryExport; + this._catalogFilter = catalogFilter; + } + + public override ExportDefinition Definition + { + get + { + return this._scopeFactoryExport.UnderlyingExportDefinition; + } + } + + protected override object GetExportedValueCore() + { + if (this._export == null) + { + // Need to create a new scopedefinition that is filtered by the ExportProvider + var filteredScopeDefinition = new CompositionScopeDefinition( + new FilteredCatalog(this._scopeFactoryExport._catalog, this._catalogFilter), + this._scopeFactoryExport._catalog.Children); + var childContainer = this._scopeFactoryExport._scopeManager.CreateChildContainer(filteredScopeDefinition); + + var export = childContainer.CatalogExportProvider.CreateExport(this._scopeFactoryExport.UnderlyingPartDefinition, this._scopeFactoryExport.UnderlyingExportDefinition, false, CreationPolicy.Any); + lock (this._lock) + { + if (this._export == null) + { + this._childContainer = childContainer; + Thread.MemoryBarrier(); + this._export = export; + + childContainer = null; + export = null; + } + } + if (childContainer != null) + { + childContainer.Dispose(); + } + } + + return this._export.Value; + } + + public void Dispose() + { + CompositionContainer childContainer = null; + Export export = null; + + if (this._export != null) + { + lock (this._lock) + { + export = this._export; + childContainer = this._childContainer; + + this._childContainer = null; + Thread.MemoryBarrier(); + this._export = null; + } + } + + if(childContainer != null) + { + childContainer.Dispose(); + } + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.ScopeManager.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.ScopeManager.cs new file mode 100644 index 00000000000..b07a961bca2 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.ScopeManager.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Text; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider + { + internal class ScopeManager : ExportProvider + { + private CompositionScopeDefinition _scopeDefinition; + private CatalogExportProvider _catalogExportProvider; + + public ScopeManager(CatalogExportProvider catalogExportProvider, CompositionScopeDefinition scopeDefinition) + { + Assumes.NotNull(catalogExportProvider); + Assumes.NotNull(scopeDefinition); + + this._scopeDefinition = scopeDefinition; + this._catalogExportProvider = catalogExportProvider; + } + + protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + List<Export> exports = new List<Export>(); + + ImportDefinition queryImport = TranslateImport(definition); + if (queryImport == null) + { + return exports; + } + + // go through the catalogs and see if there's anything there of interest + foreach (CompositionScopeDefinition childCatalog in this._scopeDefinition.Children) + { + foreach (var partDefinitionAndExportDefinition in childCatalog.GetExportsFromPublicSurface(queryImport)) + { + using (var container = this.CreateChildContainer(childCatalog)) + { + // We create a nested AtomicComposition() because the container will be Disposed and + // the RevertActions need to operate before we Dispose the child container + using (var ac = new AtomicComposition(atomicComposition)) + { + var childCatalogExportProvider = container.CatalogExportProvider; + if (!childCatalogExportProvider.DetermineRejection(partDefinitionAndExportDefinition.Item1, ac)) + { + exports.Add(this.CreateScopeExport(childCatalog, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2)); + } + } + } + } + } + + return exports; + } + + private Export CreateScopeExport(CompositionScopeDefinition childCatalog, ComposablePartDefinition partDefinition, ExportDefinition exportDefinition) + { + return new ScopeFactoryExport(this, childCatalog, partDefinition, exportDefinition); + } + + internal CompositionContainer CreateChildContainer(ComposablePartCatalog childCatalog) + { + return new CompositionContainer(childCatalog, this._catalogExportProvider._compositionOptions, this._catalogExportProvider._sourceProvider); + } + + private static ImportDefinition TranslateImport(ImportDefinition definition) + { + IPartCreatorImportDefinition factoryDefinition = definition as IPartCreatorImportDefinition; + if (factoryDefinition == null) + { + return null; + } + + // Now we need to make sure that the creation policy is handled correctly + // We will always create a new child CatalogEP to satsify the request, so from the perspecitive of the caller, the policy should + // always be NonShared (or Any). From teh perspective of the callee, it's the otehr way around. + ContractBasedImportDefinition productImportDefinition = factoryDefinition.ProductImportDefinition; + ImportDefinition result = null; + + switch (productImportDefinition.RequiredCreationPolicy) + { + case CreationPolicy.NonShared: + case CreationPolicy.NewScope: + { + // we need to recreate the import definition with the policy "Any", so that we can + // pull singletons from the inner CatalogEP. teh "non-sharedness" is achieved through + // the creation of the new EPs already. + result = new ContractBasedImportDefinition( + productImportDefinition.ContractName, + productImportDefinition.RequiredTypeIdentity, + productImportDefinition.RequiredMetadata, + productImportDefinition.Cardinality, + productImportDefinition.IsRecomposable, + productImportDefinition.IsPrerequisite, + CreationPolicy.Any, + productImportDefinition.Metadata); + break; + } + case CreationPolicy.Any: + { + // "Any" works every time + result = productImportDefinition; + break; + } + } + + return result; + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.cs new file mode 100644 index 00000000000..874bb4f5830 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExportProvider.cs @@ -0,0 +1,955 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Diagnostics; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CatalogExportProvider : ExportProvider, IDisposable + { + private class InnerCatalogExportProvider : ExportProvider + { + Func<ImportDefinition, AtomicComposition, IEnumerable<Export>> _getExportsCore; + + public InnerCatalogExportProvider(Func<ImportDefinition, AtomicComposition, IEnumerable<Export>> getExportsCore ) + { + this._getExportsCore = getExportsCore; + } + + protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + Assumes.NotNull(this._getExportsCore); + return this._getExportsCore(definition, atomicComposition); + } + } + + private readonly CompositionLock _lock; + private Dictionary<ComposablePartDefinition, CatalogPart> _activatedParts = new Dictionary<ComposablePartDefinition, CatalogPart>(); + private HashSet<ComposablePartDefinition> _rejectedParts = new HashSet<ComposablePartDefinition>(); + private ConditionalWeakTable<object, List<ComposablePart>> _gcRoots; + private HashSet<IDisposable> _partsToDispose = new HashSet<IDisposable>(); + private ComposablePartCatalog _catalog; + private volatile bool _isDisposed = false; + private volatile bool _isRunning = false; + private ExportProvider _sourceProvider; + private ImportEngine _importEngine; + private CompositionOptions _compositionOptions; + private ExportProvider _innerExportProvider; + + /// <summary> + /// Initializes a new instance of the <see cref="CatalogExportProvider"/> class. + /// </summary> + /// <param name="catalog"> + /// The <see cref="ComposablePartCatalog"/> that the <see cref="CatalogExportProvider"/> + /// uses to produce <see cref="Export"/> objects. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="catalog"/> is <see langword="null"/>. + /// </exception> + public CatalogExportProvider(ComposablePartCatalog catalog) + : this(catalog, CompositionOptions.Default) + { + } + + public CatalogExportProvider(ComposablePartCatalog catalog, bool isThreadSafe) + : this(catalog, isThreadSafe ? CompositionOptions.IsThreadSafe : CompositionOptions.Default) + { + } + + public CatalogExportProvider(ComposablePartCatalog catalog, CompositionOptions compositionOptions) + { + Requires.NotNull(catalog, "catalog"); + if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) + { + throw new ArgumentOutOfRangeException("compositionOptions"); + } + + this._catalog = catalog; + this._compositionOptions = compositionOptions; + var notifyCatalogChanged = this._catalog as INotifyComposablePartCatalogChanged; + if (notifyCatalogChanged != null) + { + notifyCatalogChanged.Changing += this.OnCatalogChanging; + } + + CompositionScopeDefinition scopeDefinition = this._catalog as CompositionScopeDefinition; + if (scopeDefinition != null) + { + this._innerExportProvider = new AggregateExportProvider(new ScopeManager(this, scopeDefinition), new InnerCatalogExportProvider(InternalGetExportsCore)); + } + else + { + this._innerExportProvider = new InnerCatalogExportProvider(InternalGetExportsCore); + } + this._lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); + } + + + /// <summary> + /// Gets the composable part catalog that the provider users to + /// produce exports. + /// </summary> + /// <value> + /// The <see cref="ComposablePartCatalog"/> that the + /// <see cref="CatalogExportProvider"/> + /// uses to produce <see cref="Export"/> objects. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public ComposablePartCatalog Catalog + { + get + { + ThrowIfDisposed(); + Contract.Ensures(Contract.Result<ComposablePartCatalog>() != null); + + return this._catalog; + } + } + + /// <summary> + /// Gets the export provider which provides the provider access to additional + /// exports. + /// </summary> + /// <value> + /// The <see cref="ExportProvider"/> which provides the + /// <see cref="CatalogExportProvider"/> access to additional + /// <see cref="Export"/> objects. The default is <see langword="null"/>. + /// </value> + /// <exception cref="ArgumentNullException"> + /// <paramref name="value"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="InvalidOperationException"> + /// This property has already been set. + /// <para> + /// -or- + /// </para> + /// The methods on the <see cref="CatalogExportProvider"/> + /// have already been accessed. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CatalogExportProvider"/> has been disposed of. + /// </exception> + /// <remarks> + /// This property must be set before accessing any methods on the + /// <see cref="CatalogExportProvider"/>. + /// </remarks> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification="EnsureCanSet ensures that the property is set only once, Dispose is not required")] + public ExportProvider SourceProvider + { + get + { + this.ThrowIfDisposed(); + using (this._lock.LockStateForRead()) + { + return this._sourceProvider; + } + } + set + { + this.ThrowIfDisposed(); + + Requires.NotNull(value, "value"); + + ImportEngine newImportEngine = null; + AggregateExportProvider aggregateExportProvider = null; + ExportProvider sourceProvider = value; + + bool isThrowing = true; + try + { + newImportEngine = new ImportEngine(sourceProvider, this._compositionOptions); + + sourceProvider.ExportsChanging += this.OnExportsChangingInternal; + + using (this._lock.LockStateForWrite()) + { + this.EnsureCanSet(this._sourceProvider); + + this._sourceProvider = sourceProvider; + this._importEngine = newImportEngine; + + isThrowing = false; + } + } + finally + { + if (isThrowing) + { + sourceProvider.ExportsChanging -= this.OnExportsChangingInternal; + newImportEngine.Dispose(); + if (aggregateExportProvider != null) + { + aggregateExportProvider.Dispose(); + } + } + } + } + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (!this._isDisposed) + { + bool disposeLock = false; + INotifyComposablePartCatalogChanged catalogToUnsubscribeFrom = null; + HashSet<IDisposable> partsToDispose = null; + ImportEngine importEngine = null; + ExportProvider sourceProvider = null; + AggregateExportProvider aggregateExportProvider = null; + try + { + using (this._lock.LockStateForWrite()) + { + if (!this._isDisposed) + { + catalogToUnsubscribeFrom = this._catalog as INotifyComposablePartCatalogChanged; + this._catalog = null; + + aggregateExportProvider = this._innerExportProvider as AggregateExportProvider; + this._innerExportProvider = null; + + sourceProvider = this._sourceProvider; + this._sourceProvider = null; + + importEngine = this._importEngine; + this._importEngine = null; + + partsToDispose = this._partsToDispose; + this._gcRoots = null; + + disposeLock = true; + this._isDisposed = true; + + } + } + } + finally + { + if (catalogToUnsubscribeFrom != null) + { + catalogToUnsubscribeFrom.Changing -= this.OnCatalogChanging; + } + + if (aggregateExportProvider != null) + { + aggregateExportProvider.Dispose(); + } + + if (sourceProvider != null) + { + sourceProvider.ExportsChanging -= this.OnExportsChangingInternal; + } + + if (importEngine != null) + { + importEngine.Dispose(); + } + + if (partsToDispose != null) + { + foreach (var part in partsToDispose) + { + part.Dispose(); + } + } + + if (disposeLock) + { + this._lock.Dispose(); + } + } + } + } + } + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> to get.</param> + /// <returns></returns> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <remarks> + /// <note type="inheritinfo"> + /// The implementers should not treat the cardinality-related mismatches as errors, and are not + /// expected to throw exceptions in those cases. + /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, + /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. + /// </note> + /// </remarks> + protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + Assumes.NotNull(this._innerExportProvider); + + IEnumerable<Export> exports; + this._innerExportProvider.TryGetExports(definition, atomicComposition, out exports); + return exports; + } + + private IEnumerable<Export> InternalGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + // Use the version of the catalog appropriate to this atomicComposition + ComposablePartCatalog currentCatalog = atomicComposition.GetValueAllowNull(this._catalog); + + IPartCreatorImportDefinition partCreatorDefinition = definition as IPartCreatorImportDefinition; + bool isExportFactory = false; + + if (partCreatorDefinition != null) + { + definition = partCreatorDefinition.ProductImportDefinition; + isExportFactory = true; + } + + CreationPolicy importPolicy = definition.GetRequiredCreationPolicy(); + + List<Export> exports = new List<Export>(); + foreach (var partDefinitionAndExportDefinition in currentCatalog.GetExports(definition)) + { + if (!this.IsRejected(partDefinitionAndExportDefinition.Item1, atomicComposition)) + { + exports.Add(this.CreateExport(partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2, isExportFactory, importPolicy)); + } + } + + return exports; + } + + private Export CreateExport(ComposablePartDefinition partDefinition, ExportDefinition exportDefinition, bool isExportFactory, CreationPolicy importPolicy) + { + if (isExportFactory) + { + return new PartCreatorExport(this, + partDefinition, + exportDefinition); + } + else + { + return CatalogExport.CreateExport(this, + partDefinition, + exportDefinition, + importPolicy); + } + } + + + + private void OnExportsChangingInternal(object sender, ExportsChangeEventArgs e) + { + UpdateRejections(e.AddedExports.Concat(e.RemovedExports), e.AtomicComposition); + } + + private static ExportDefinition[] GetExportsFromPartDefinitions(IEnumerable<ComposablePartDefinition> partDefinitions) + { + List<ExportDefinition> exports = new List<ExportDefinition>(); + + foreach (var partDefinition in partDefinitions) + { + foreach (var export in partDefinition.ExportDefinitions) + { + exports.Add(export); + + // While creating a PartCreatorExportDefinition for every changed definition may not be the most + // efficient way to do this the PartCreatorExportDefinition is very efficient and doesn't do any + // real work unless its metadata is pulled on. If this turns out to be a bottleneck then we + // will need to start tracking all the PartCreator's we hand out and only send those which we + // have handed out. In fact we could do the same thing for all the Exports if we wished but + // that requires a cache management which we don't want to do at this point. + exports.Add(new PartCreatorExportDefinition(export)); + } + } + + return exports.ToArray(); + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + private void OnCatalogChanging(object sender, ComposablePartCatalogChangeEventArgs e) + { + using (var atomicComposition = new AtomicComposition(e.AtomicComposition)) + { + // Save the preview catalog to use in place of the original while handling + // this event + atomicComposition.SetValue(this._catalog, + new CatalogChangeProxy(this._catalog, e.AddedDefinitions, e.RemovedDefinitions)); + + IEnumerable<ExportDefinition> addedExports = GetExportsFromPartDefinitions(e.AddedDefinitions); + IEnumerable<ExportDefinition> removedExports = GetExportsFromPartDefinitions(e.RemovedDefinitions); + + // Remove any parts based on eliminated definitions (in a atomicComposition-friendly + // fashion) + foreach (var definition in e.RemovedDefinitions) + { + CatalogPart removedPart = null; + bool removed = false; + + using (this._lock.LockStateForRead()) + { + removed = this._activatedParts.TryGetValue(definition, out removedPart); + } + + if (removed) + { + var capturedDefinition = definition; + this.ReleasePart(null, removedPart, atomicComposition); + atomicComposition.AddCompleteActionAllowNull(() => + { + using (this._lock.LockStateForWrite()) + { + this._activatedParts.Remove(capturedDefinition); + } + }); + } + } + + UpdateRejections(addedExports.ConcatAllowingNull(removedExports), atomicComposition); + + this.OnExportsChanging( + new ExportsChangeEventArgs(addedExports, removedExports, atomicComposition)); + + atomicComposition.AddCompleteAction(() => this.OnExportsChanged( + new ExportsChangeEventArgs(addedExports, removedExports, null))); + + atomicComposition.Complete(); + } + } + + private CatalogPart GetComposablePart(ComposablePartDefinition partDefinition, bool isSharedPart) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + CatalogPart catalogPart = null; + + if (isSharedPart) + { + catalogPart = this.GetSharedPart(partDefinition); + } + else + { + ComposablePart part = partDefinition.CreatePart(); + catalogPart = new CatalogPart(part); + + IDisposable disposablePart = part as IDisposable; + if (disposablePart != null) + { + using (this._lock.LockStateForWrite()) + { + this._partsToDispose.Add(disposablePart); + } + } + } + + return catalogPart; + } + + private CatalogPart GetSharedPart(ComposablePartDefinition partDefinition) + { + CatalogPart catalogPart = null; + + // look up the part + using (this._lock.LockStateForRead()) + { + if (this._activatedParts.TryGetValue(partDefinition, out catalogPart)) + { + return catalogPart; + } + } + + // create a part outside of the lock + ComposablePart newPart = partDefinition.CreatePart(); + IDisposable disposableNewPart = newPart as IDisposable; + + using (this._lock.LockStateForWrite()) + { + // check if the part is still not there + if (!this._activatedParts.TryGetValue(partDefinition, out catalogPart)) + { + catalogPart = new CatalogPart(newPart); + this._activatedParts.Add(partDefinition, catalogPart); + if (disposableNewPart != null) + { + this._partsToDispose.Add(disposableNewPart); + } + + // indiacate the the part has been added + newPart = null; + disposableNewPart = null; + } + } + + // if disposableNewPart != null, this means we have created a new instance of something disposable and not used it + // Dispose of it now + if (disposableNewPart != null) + { + disposableNewPart.Dispose(); + } + + return catalogPart; + } + + private object GetExportedValue(CatalogPart part, ExportDefinition export, bool isSharedPart) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + Assumes.NotNull(part, export); + + // We don't protect against thread racing here, as "importsSatisfied" is merely an optimization + // if two threads satisfy imports twice, the results is the same, just the perf hit is heavier. + + bool importsSatisfied = part.ImportsSatisfied; + ImportEngine importEngine = importsSatisfied ? null : this._importEngine; + + object exportedValue = CompositionServices.GetExportedValueFromComposedPart( + importEngine, part.Part, export); + + if (!importsSatisfied) + { + // and set "ImportsSatisfied" to true + part.ImportsSatisfied = true; + } + + // Only hold conditional references for recomposable non-shared parts because we are + // already holding strong references to the shared parts. + if (exportedValue != null && !isSharedPart && part.Part.IsRecomposable()) + { + this.PreventPartCollection(exportedValue, part.Part); + } + + return exportedValue; + } + + private void ReleasePart(object exportedValue, CatalogPart catalogPart, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + Assumes.NotNull(catalogPart); + + this._importEngine.ReleaseImports(catalogPart.Part, atomicComposition); + + if (exportedValue != null) + { + atomicComposition.AddCompleteActionAllowNull(() => + { + this.AllowPartCollection(exportedValue); + }); + } + + IDisposable diposablePart = catalogPart.Part as IDisposable; + if (diposablePart != null) + { + atomicComposition.AddCompleteActionAllowNull(() => + { + bool removed = false; + using (this._lock.LockStateForWrite()) + { + removed = this._partsToDispose.Remove(diposablePart); + } + if (removed) + { + diposablePart.Dispose(); + } + }); + } + } + + private void PreventPartCollection(object exportedValue, ComposablePart part) + { + Assumes.NotNull(exportedValue, part); + + using (this._lock.LockStateForWrite()) + { + List<ComposablePart> partList; + + ConditionalWeakTable<object, List<ComposablePart>> gcRoots = this._gcRoots; + if (gcRoots == null) + { + gcRoots = new ConditionalWeakTable<object, List<ComposablePart>>(); + } + + if (!gcRoots.TryGetValue(exportedValue, out partList)) + { + partList = new List<ComposablePart>(); + gcRoots.Add(exportedValue, partList); + } + + partList.Add(part); + + if (this._gcRoots == null) + { + Thread.MemoryBarrier(); + this._gcRoots = gcRoots; + } + } + } + + private void AllowPartCollection(object gcRoot) + { + if (this._gcRoots != null) + { + using (this._lock.LockStateForWrite()) + { + this._gcRoots.Remove(gcRoot); + } + } + } + + private bool IsRejected(ComposablePartDefinition definition, AtomicComposition atomicComposition) + { + // Check to see if we're currently working on the definition in question. + // Recursive queries always answer optimistically, as if the definition hasn't + // been rejected - because if it is we can discard all decisions that were based + // on the faulty assumption in the first place. + var forceRejectionTest = false; + if (atomicComposition != null) + { + var atomicCompositionQuery = GetAtomicCompositionQuery(atomicComposition); + AtomicCompositionQueryState state = atomicCompositionQuery(definition); + switch (state) + { + case AtomicCompositionQueryState.TreatAsRejected: + return true; + case AtomicCompositionQueryState.TreatAsValidated: + return false; + case AtomicCompositionQueryState.NeedsTesting: + forceRejectionTest = true; + break; + default: + Assumes.IsTrue(state == AtomicCompositionQueryState.Unknown); + // Need to do the work to determine the state + break; + } + } + + if (!forceRejectionTest) + { + // Next, anything that has been activated is not rejected + using (this._lock.LockStateForRead()) + { + if (this._activatedParts.ContainsKey(definition)) + { + return false; + } + + // Last stop before doing the hard work: check a specific registry of rejected parts + if (this._rejectedParts.Contains(definition)) + { + return true; + } + } + } + + // Determine whether or not the definition's imports can be satisfied + return DetermineRejection(definition, atomicComposition); + } + + private bool DetermineRejection(ComposablePartDefinition definition, AtomicComposition parentAtomicComposition) + { + ChangeRejectedException exception = null; + + using (var localAtomicComposition = new AtomicComposition(parentAtomicComposition)) + { + // The part definition we're currently working on is treated optimistically + // as if we know it hasn't been rejected. This handles recursion, and if we + // later decide that it has been rejected we'll discard all nested progress so + // all side-effects of the mistake are erased. + // + // Note that this means that recursive failures that would be detected by the + // import engine are not discovered by rejection currently. Loops among + // prerequisites, runaway import chains involving factories, and prerequisites + // that cannot be fully satisfied still result in runtime errors. Doing + // otherwise would be possible but potentially expensive - and could be a v2 + // improvement if deemed worthwhile. + UpdateAtomicCompositionQuery(localAtomicComposition, + def => definition.Equals(def), AtomicCompositionQueryState.TreatAsValidated); + + var newPart = definition.CreatePart(); + try + { + this._importEngine.PreviewImports(newPart, localAtomicComposition); + + // Reuse the partially-fleshed out part the next time we need a shared + // instance to keep the expense of pre-validation to a minimum. Note that + // _activatedParts holds references to both shared and non-shared parts. + // The non-shared parts will only be used for rejection purposes only but + // the shared parts will be handed out when requested via GetExports as + // well as be used for rejection purposes. + localAtomicComposition.AddCompleteActionAllowNull(() => + { + using (this._lock.LockStateForWrite()) + { + if (!this._activatedParts.ContainsKey(definition)) + { + this._activatedParts.Add(definition, new CatalogPart(newPart)); + IDisposable newDisposablePart = newPart as IDisposable; + if (newDisposablePart != null) + { + this._partsToDispose.Add(newDisposablePart); + } + } + } + }); + + // Success! Complete any recursive work that was conditioned on this part's validation + localAtomicComposition.Complete(); + + return false; + } + catch (ChangeRejectedException ex) + { + exception = ex; + } + } + + // If we've reached this point then this part has been rejected so we need to + // record the rejection in our parent composition or execute it immediately if + // one doesn't exist. + parentAtomicComposition.AddCompleteActionAllowNull(() => + { + using (this._lock.LockStateForWrite()) + { + this._rejectedParts.Add(definition); + } + + CompositionTrace.PartDefinitionRejected(definition, exception); + + }); + if (parentAtomicComposition != null) + { + UpdateAtomicCompositionQuery(parentAtomicComposition, + def => definition.Equals(def), AtomicCompositionQueryState.TreatAsRejected); + } + + return true; + } + + private void UpdateRejections(IEnumerable<ExportDefinition> changedExports, AtomicComposition atomicComposition) + { + using (var localAtomicComposition = new AtomicComposition(atomicComposition)) + { + // Reconsider every part definition that has been previously + // rejected to see if any of them can be added back. + var affectedRejections = new HashSet<ComposablePartDefinition>(); + var atomicCompositionQuery = GetAtomicCompositionQuery(localAtomicComposition); + + ComposablePartDefinition[] rejectedParts; + using (this._lock.LockStateForRead()) + { + rejectedParts = this._rejectedParts.ToArray(); + } + foreach (var definition in rejectedParts) + { + if (atomicCompositionQuery(definition) == AtomicCompositionQueryState.TreatAsValidated) + { + continue; + } + + foreach (var import in definition.ImportDefinitions.Where(ImportEngine.IsRequiredImportForPreview)) + { + if (changedExports.Any(export => import.IsConstraintSatisfiedBy(export))) + { + affectedRejections.Add(definition); + break; + } + } + } + UpdateAtomicCompositionQuery(localAtomicComposition, + def => affectedRejections.Contains(def), AtomicCompositionQueryState.NeedsTesting); + + // Determine if any of the resurrectable parts is now available so that we can + // notify listeners of the exact changes to exports + var resurrectedExports = new List<ExportDefinition>(); + + foreach (var partDefinition in affectedRejections) + { + if (!IsRejected(partDefinition, localAtomicComposition)) + { + // Notify listeners of the newly available exports and + // prepare to remove the rejected part from the list of rejections + resurrectedExports.AddRange(partDefinition.ExportDefinitions); + + // Capture the local so that the closure below refers to the current definition + // in the loop and not the value of 'partDefinition' when the closure executes + var capturedPartDefinition = partDefinition; + localAtomicComposition.AddCompleteAction(() => + { + using (this._lock.LockStateForWrite()) + { + this._rejectedParts.Remove(capturedPartDefinition); + } + + CompositionTrace.PartDefinitionResurrected(capturedPartDefinition); + }); + } + } + + // Notify anyone sourcing exports that the resurrected exports have appeared + if (resurrectedExports.Any()) + { + this.OnExportsChanging( + new ExportsChangeEventArgs(resurrectedExports, new ExportDefinition[0], localAtomicComposition)); + + localAtomicComposition.AddCompleteAction(() => this.OnExportsChanged( + new ExportsChangeEventArgs(resurrectedExports, new ExportDefinition[0], null))); + } + + localAtomicComposition.Complete(); + } + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + /// <summary> + /// EnsureCanRun must be called from within a lock. + /// </summary> + [DebuggerStepThrough] + private void EnsureCanRun() + { + if ((this._sourceProvider == null) || (this._importEngine == null)) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ObjectMustBeInitialized, "SourceProvider")); // NOLOC + } + } + + [DebuggerStepThrough] + private void EnsureRunning() + { + if (!this._isRunning) + { + using (this._lock.LockStateForWrite()) + { + if (!this._isRunning) + { + this.EnsureCanRun(); + this._isRunning = true; + } + } + } + } + + /// <summary> + /// EnsureCanSet<T> must be called from within a lock. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="currentValue"></param> + [DebuggerStepThrough] + private void EnsureCanSet<T>(T currentValue) + where T : class + { + if ((this._isRunning) || (currentValue != null)) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ObjectAlreadyInitialized)); + } + } + + private Func<ComposablePartDefinition, AtomicCompositionQueryState> GetAtomicCompositionQuery(AtomicComposition atomicComposition) + { + Func<ComposablePartDefinition, AtomicCompositionQueryState> atomicCompositionQuery; + atomicComposition.TryGetValue(this, out atomicCompositionQuery); + + if (atomicCompositionQuery == null) + { + return (definition) => AtomicCompositionQueryState.Unknown; + } + + return atomicCompositionQuery; + } + + private void UpdateAtomicCompositionQuery( + AtomicComposition atomicComposition, + Func<ComposablePartDefinition, bool> query, + AtomicCompositionQueryState state) + { + var parentQuery = GetAtomicCompositionQuery(atomicComposition); + Func<ComposablePartDefinition, AtomicCompositionQueryState> newQuery = definition => + { + if (query(definition)) + { + return state; + } + return parentQuery(definition); + }; + + atomicComposition.SetValue(this, newQuery); + } + + private enum AtomicCompositionQueryState + { + Unknown, + TreatAsRejected, + TreatAsValidated, + NeedsTesting + }; + + private class CatalogPart + { + private volatile bool _importsSatisfied = false; + public CatalogPart(ComposablePart part) + { + this.Part = part; + } + public ComposablePart Part { get; private set; } + + public bool ImportsSatisfied + { + get + { + return this._importsSatisfied; + } + set + { + this._importsSatisfied = value; + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExtensions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExtensions.cs new file mode 100644 index 00000000000..15308a2380b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CatalogExtensions.cs @@ -0,0 +1,26 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public static class CatalogExtensions + { + /// <summary> + /// Creates a <see cref="CompositionService"/>. + /// </summary> + /// <param name="catalog">The catalog.</param> + /// <returns>The newly created <see cref="CompositionService"/> + public static CompositionService CreateCompositionService(this ComposablePartCatalog composablePartCatalog) + { + Requires.NotNull(composablePartCatalog, "composablePartCatalog"); + + return new CompositionService(composablePartCatalog); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogChangeEventArgs.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogChangeEventArgs.cs new file mode 100644 index 00000000000..b7ff41a7fc3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogChangeEventArgs.cs @@ -0,0 +1,101 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.Contracts; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// Provides data for the <see cref="INotifyComposablePartCatalogChanged.Changed"/> and + /// <see cref="INotifyComposablePartCatalogChanged.Changing"/> events. + /// </summary> + public class ComposablePartCatalogChangeEventArgs : EventArgs + { + private readonly IEnumerable<ComposablePartDefinition> _addedDefinitions; + private readonly IEnumerable<ComposablePartDefinition> _removedDefinitions; + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartCatalogChangeEventArgs"/>. + /// </summary> + /// <param name="addedDefinitions"> + /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that + /// are being added to the <see cref="ComposablePartCatalog"/>. + /// </param> + /// <param name="removedDefinitions"> + /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that + /// are being removed from the <see cref="ComposablePartCatalog"/>. + /// </param> + /// <param name="atomicComposition"> + /// A <see cref="AtomicComposition"/> representing all tentative changes that will + /// be completed if the change is successful, or discarded if it is not. + /// <see langword="null"/> if being applied outside a <see cref="AtomicComposition"/> + /// or during a <see cref="INotifyComposablePartCatalogChanged.Changed"/> event. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="addedDefinitions"/> or <paramref name="removedDefinitions"/> is <see langword="null"/>. + /// </exception> + public ComposablePartCatalogChangeEventArgs(IEnumerable<ComposablePartDefinition> addedDefinitions, + IEnumerable<ComposablePartDefinition> removedDefinitions, AtomicComposition atomicComposition) + { + Requires.NotNull(addedDefinitions, "addedDefinitions"); + Requires.NotNull(removedDefinitions, "removedDefinitions"); + + this._addedDefinitions = addedDefinitions.AsArray(); + this._removedDefinitions = removedDefinitions.AsArray(); + this.AtomicComposition = atomicComposition; + } + + /// <summary> + /// Gets the identifiers of the parts that have been added. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that + /// have been added to the <see cref="ComposablePartCatalog"/>. + /// </value> + public IEnumerable<ComposablePartDefinition> AddedDefinitions + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ComposablePartDefinition>>() != null); + + return this._addedDefinitions; + } + } + + /// <summary> + /// Gets the identifiers of the parts that have been removed. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that + /// have been removed from from the <see cref="ComposablePartCatalog"/>. + /// </value> + public IEnumerable<ComposablePartDefinition> RemovedDefinitions + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ComposablePartDefinition>>() != null); + + return this._removedDefinitions; + } + } + + /// <summary> + /// Gets the atomicComposition, if any, that this change applies to. + /// </summary> + /// <value> + /// A <see cref="AtomicComposition"/> that this set of changes applies too. + /// It can be <see langword="null"/> if the changes are being applied outside a + /// <see cref="AtomicComposition"/> or during a + /// <see cref="INotifyComposablePartCatalogChanged.Changed"/> event. + /// + /// When the value is non-null it should be used to record temporary changed state + /// and actions that will be executed when the atomicComposition is completeed. + /// </value> + public AtomicComposition AtomicComposition { get; private set; } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs new file mode 100644 index 00000000000..151162887fc --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs @@ -0,0 +1,415 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Text; +using System.Threading; +using System.Diagnostics; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// This class implements a threadsafe ICollection{T} of ComposablePartCatalog. + /// It is exposed as an ICollection(ComposablePartCatalog) + /// It is threadsafe, notifications are not marshalled using a SynchronizationContext. + /// It is Disposable. + /// </summary> + internal class ComposablePartCatalogCollection : ICollection<ComposablePartCatalog>, INotifyComposablePartCatalogChanged, IDisposable + { + private readonly Lock _lock = new Lock(); + private Action<ComposablePartCatalogChangeEventArgs> _onChanged; + private Action<ComposablePartCatalogChangeEventArgs> _onChanging; + private List<ComposablePartCatalog> _catalogs = new List<ComposablePartCatalog>(); + private volatile bool _isCopyNeeded = false; + private volatile bool _isDisposed = false; + private bool _hasChanged = false; + + public ComposablePartCatalogCollection( + IEnumerable<ComposablePartCatalog> catalogs, + Action<ComposablePartCatalogChangeEventArgs> onChanged, + Action<ComposablePartCatalogChangeEventArgs> onChanging) + { + catalogs = catalogs ?? Enumerable.Empty<ComposablePartCatalog>(); + this._catalogs = new List<ComposablePartCatalog>(catalogs); + this._onChanged = onChanged; + this._onChanging = onChanging; + + SubscribeToCatalogNotifications(catalogs); + } + + public void Add(ComposablePartCatalog item) + { + Requires.NotNull(item, "item"); + + this.ThrowIfDisposed(); + + var addedParts = new Lazy<IEnumerable<ComposablePartDefinition>>(() => item.ToArray(), LazyThreadSafetyMode.PublicationOnly); + + using (var atomicComposition = new AtomicComposition()) + { + this.RaiseChangingEvent(addedParts, null, atomicComposition); + + using (new WriteLock(this._lock)) + { + if (this._isCopyNeeded) + { + this._catalogs = new List<ComposablePartCatalog>(this._catalogs); + this._isCopyNeeded = false; + } + this._hasChanged = true; + this._catalogs.Add(item); + } + + this.SubscribeToCatalogNotifications(item); + + // Complete after the catalog changes are written + atomicComposition.Complete(); + } + + this.RaiseChangedEvent(addedParts, null); + } + + /// <summary> + /// Notify when the contents of the Catalog has changed. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed; + + /// <summary> + /// Notify when the contents of the Catalog has changing. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing; + + public void Clear() + { + this.ThrowIfDisposed(); + + // No action is required if we are already empty + ComposablePartCatalog[] catalogs = null; + using (new ReadLock(this._lock)) + { + if (this._catalogs.Count == 0) + { + return; + } + catalogs = this._catalogs.ToArray(); + } + + //TODO-MT: This is pretty suspect - we can easily eliminate catalogs that aren't listed as being + // removed. Then again, the idea of trying to mutate the catalog on two threads at the same time is pretty + // suspect to begin with. When would that ever result in a meaningful composition? + + // We are doing this outside of the lock, so it's possible that the catalog will continute propagating events from things + // we are about to unsubscribe from. Given the non-specificity of our event, in the worst case scenario we would simply fire + // unnecessary events. + + var removedParts = new Lazy<IEnumerable<ComposablePartDefinition>>(() => catalogs.SelectMany(catalog => catalog).ToArray(), LazyThreadSafetyMode.PublicationOnly); + + // Validate the changes before applying them + using (var atomicComposition = new AtomicComposition()) + { + this.RaiseChangingEvent(null, removedParts, atomicComposition); + this.UnsubscribeFromCatalogNotifications(catalogs); + + using (new WriteLock(this._lock)) + { + this._catalogs = new List<ComposablePartCatalog>(); + + this._isCopyNeeded = false; + this._hasChanged = true; + } + + // Complete after the catalog changes are written + atomicComposition.Complete(); + } + + this.RaiseChangedEvent(null, removedParts); + } + + public bool Contains(ComposablePartCatalog item) + { + Requires.NotNull(item, "item"); + + this.ThrowIfDisposed(); + + using (new ReadLock(this._lock)) + { + return this._catalogs.Contains(item); + } + } + + public void CopyTo(ComposablePartCatalog[] array, int arrayIndex) + { + this.ThrowIfDisposed(); + + using (new ReadLock(this._lock)) + { + this._catalogs.CopyTo(array, arrayIndex); + } + } + + public int Count + { + get + { + this.ThrowIfDisposed(); + + using (new ReadLock(this._lock)) + { + return this._catalogs.Count; + } + } + } + + public bool IsReadOnly + { + get + { + this.ThrowIfDisposed(); + + return false; + } + } + + public bool Remove(ComposablePartCatalog item) + { + Requires.NotNull(item, "item"); + + this.ThrowIfDisposed(); + + using (new ReadLock(this._lock)) + { + if (!this._catalogs.Contains(item)) + { + return false; + } + } + + bool isSuccessfulRemoval = false; + + var removedParts = new Lazy<IEnumerable<ComposablePartDefinition>>(() => item.ToArray(), LazyThreadSafetyMode.PublicationOnly); + using (var atomicComposition = new AtomicComposition()) + { + this.RaiseChangingEvent(null, removedParts, atomicComposition); + + using (new WriteLock(this._lock)) + { + if (_isCopyNeeded) + { + this._catalogs = new List<ComposablePartCatalog>(this._catalogs); + this._isCopyNeeded = false; + } + + isSuccessfulRemoval = this._catalogs.Remove(item); + if (isSuccessfulRemoval) + { + this._hasChanged = true; + } + } + + this.UnsubscribeFromCatalogNotifications(item); + + // Complete after the catalog changes are written + atomicComposition.Complete(); + } + + this.RaiseChangedEvent(null, removedParts); + + return isSuccessfulRemoval; + } + + internal bool HasChanged + { + get + { + this.ThrowIfDisposed(); + + using (new ReadLock(this._lock)) + { + return this._hasChanged; + } + } + } + + public IEnumerator<ComposablePartCatalog> GetEnumerator() + { + this.ThrowIfDisposed(); + + using (new WriteLock(this._lock)) + { + IEnumerator<ComposablePartCatalog> enumerator = this._catalogs.GetEnumerator(); + this._isCopyNeeded = true; + return enumerator; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (!this._isDisposed) + { + bool disposeLock = false; + IEnumerable<ComposablePartCatalog> catalogs = null; + try + { + using (new WriteLock(this._lock)) + { + if (!this._isDisposed) + { + disposeLock = true; + + catalogs = this._catalogs; + this._catalogs = null; + + this._isDisposed = true; + } + } + } + finally + { + if (catalogs != null) + { + this.UnsubscribeFromCatalogNotifications(catalogs); + catalogs.ForEach(catalog => catalog.Dispose()); + } + + if (disposeLock) + { + this._lock.Dispose(); + } + } + } + } + } + + private void RaiseChangedEvent( + Lazy<IEnumerable<ComposablePartDefinition>> addedDefinitions, + Lazy<IEnumerable<ComposablePartDefinition>> removedDefinitions) + { + if (this._onChanged == null || this.Changed == null) + { + return; + } + + var added = (addedDefinitions == null ? Enumerable.Empty<ComposablePartDefinition>() : addedDefinitions.Value); + var removed = (removedDefinitions == null ? Enumerable.Empty<ComposablePartDefinition>() : removedDefinitions.Value); + + this._onChanged.Invoke(new ComposablePartCatalogChangeEventArgs(added, removed, null)); + } + + public void OnChanged(object sender, ComposablePartCatalogChangeEventArgs e) + { + var changedEvent = this.Changed; + if (changedEvent != null) + { + changedEvent(sender, e); + } + } + + private void RaiseChangingEvent( + Lazy<IEnumerable<ComposablePartDefinition>> addedDefinitions, + Lazy<IEnumerable<ComposablePartDefinition>> removedDefinitions, + AtomicComposition atomicComposition) + { + if (this._onChanging == null || this.Changing == null) + { + return; + } + var added = (addedDefinitions == null ? Enumerable.Empty<ComposablePartDefinition>() : addedDefinitions.Value); + var removed = (removedDefinitions == null ? Enumerable.Empty<ComposablePartDefinition>() : removedDefinitions.Value); + + this._onChanging.Invoke(new ComposablePartCatalogChangeEventArgs(added, removed, atomicComposition)); + } + + public void OnChanging(object sender, ComposablePartCatalogChangeEventArgs e) + { + var changingEvent = this.Changing; + if (changingEvent != null) + { + changingEvent(sender, e); + } + } + + private void OnContainedCatalogChanged(object sender, ComposablePartCatalogChangeEventArgs e) + { + if (this._onChanged == null || this.Changed == null) + { + return; + } + + this._onChanged.Invoke(e); + } + + private void OnContainedCatalogChanging(object sender, ComposablePartCatalogChangeEventArgs e) + { + if (this._onChanging == null || this.Changing == null) + { + return; + } + + this._onChanging.Invoke(e); + } + + private void SubscribeToCatalogNotifications(ComposablePartCatalog catalog) + { + INotifyComposablePartCatalogChanged notifyCatalog = catalog as INotifyComposablePartCatalogChanged; + if (notifyCatalog != null) + { + notifyCatalog.Changed += this.OnContainedCatalogChanged; + notifyCatalog.Changing += this.OnContainedCatalogChanging; + } + } + + private void SubscribeToCatalogNotifications(IEnumerable<ComposablePartCatalog> catalogs) + { + foreach (var catalog in catalogs) + { + SubscribeToCatalogNotifications(catalog); + } + } + + private void UnsubscribeFromCatalogNotifications(ComposablePartCatalog catalog) + { + INotifyComposablePartCatalogChanged notifyCatalog = catalog as INotifyComposablePartCatalogChanged; + if (notifyCatalog != null) + { + notifyCatalog.Changed -= this.OnContainedCatalogChanged; + notifyCatalog.Changing -= this.OnContainedCatalogChanging; + } + } + + private void UnsubscribeFromCatalogNotifications(IEnumerable<ComposablePartCatalog> catalogs) + { + foreach (var catalog in catalogs) + { + UnsubscribeFromCatalogNotifications(catalog); + } + } + + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartExportProvider.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartExportProvider.cs new file mode 100644 index 00000000000..dc0bc251be4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartExportProvider.cs @@ -0,0 +1,449 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public class ComposablePartExportProvider : ExportProvider, IDisposable + { + private List<ComposablePart> _parts = new List<ComposablePart>(); + private volatile bool _isDisposed = false; + private volatile bool _isRunning = false; + private CompositionLock _lock = null; + private ExportProvider _sourceProvider; + private ImportEngine _importEngine; + private volatile bool _currentlyComposing; + private CompositionOptions _compositionOptions; + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartExportProvider"/> class. + /// </summary> + public ComposablePartExportProvider() : + this(false) + { + } + + public ComposablePartExportProvider(bool isThreadSafe) + :this(isThreadSafe ? CompositionOptions.IsThreadSafe : CompositionOptions.Default) + { + } + + public ComposablePartExportProvider(CompositionOptions compositionOptions) + { + if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) + { + throw new ArgumentOutOfRangeException("compositionOptions"); + } + + this._compositionOptions = compositionOptions; + this._lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (!this._isDisposed) + { + bool disposeLock = false; + ImportEngine importEngine = null; + try + { + using (this._lock.LockStateForWrite()) + { + if (!this._isDisposed) + { + importEngine = this._importEngine; + this._importEngine = null; + + this._sourceProvider = null; + this._isDisposed = true; + disposeLock = true; + } + } + } + finally + { + if (importEngine != null) + { + importEngine.Dispose(); + } + + if (disposeLock) + { + this._lock.Dispose(); + } + } + } + } + } + + /// <summary> + /// Gets the export provider which provides the provider access to + /// exports. + /// </summary> + /// <value> + /// The <see cref="ExportProvider"/> which provides the + /// <see cref="ComposablePartExportProvider"/> access to <see cref="Export"/> objects. + /// The default is <see langword="null"/>. + /// </value> + /// <exception cref="ArgumentNullException"> + /// <paramref name="value"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="InvalidOperationException"> + /// This property has already been set. + /// <para> + /// -or- + /// </para> + /// The methods on the <see cref="ComposablePartExportProvider"/> + /// have already been accessed. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePartExportProvider"/> has been disposed of. + /// </exception> + /// <remarks> + /// This property must be set before accessing any methods on the + /// <see cref="ComposablePartExportProvider"/>. + /// </remarks> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "EnsureCanSet ensures that the property is set only once, Dispose is not required")] + public ExportProvider SourceProvider + { + get + { + this.ThrowIfDisposed(); + + return this._sourceProvider; + } + set + { + this.ThrowIfDisposed(); + + Requires.NotNull(value, "value"); + using (this._lock.LockStateForWrite()) + { + this.EnsureCanSet(this._sourceProvider); + this._sourceProvider = value; + } + } + } + + private ImportEngine ImportEngine + { + get + { + if (this._importEngine == null) + { + Assumes.NotNull(this._sourceProvider); + ImportEngine importEngine = new ImportEngine(this._sourceProvider, this._compositionOptions); + using (this._lock.LockStateForWrite()) + { + if (this._importEngine == null) + { + Thread.MemoryBarrier(); + this._importEngine = importEngine; + importEngine = null; + } + } + + // if we have created an engine and didn't set it because of a race condition, we need to dispose of it + if (importEngine != null) + { + importEngine.Dispose(); + } + } + + return this._importEngine; + } + } + + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> to get.</param> + /// <returns></returns> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <remarks> + /// <note type="inheritinfo"> + /// The implementers should not treat the cardinality-related mismatches as errors, and are not + /// expected to throw exceptions in those cases. + /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, + /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. + /// </note> + /// </remarks> + protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + // Determine whether there is a composition atomicComposition-specific list of parts to use, + // failing that use the usual list. We never change the list of parts in place, + // but rather copy, change and write a new list atomically. Therefore all we need + // to do here is to read the _parts member. + List<ComposablePart> parts = null; + using (this._lock.LockStateForRead()) + { + parts = atomicComposition.GetValueAllowNull(this, this._parts); + } + + if (parts.Count == 0) + { + return null; + } + + List<Export> exports = new List<Export>(); + foreach (var part in parts) + { + foreach (var exportDefinition in part.ExportDefinitions) + { + if (definition.IsConstraintSatisfiedBy(exportDefinition)) + { + exports.Add(this.CreateExport(part, exportDefinition)); + } + } + } + return exports; + } + + public void Compose(CompositionBatch batch) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + Requires.NotNull(batch, "batch"); + + // Quick exit test can be done prior to cloning since it's just an optimization, not a + // change in behavior + if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0)) + { + return; + } + + CompositionResult result = CompositionResult.SucceededResult; + + // Get updated parts list and a cloned batch + var newParts = GetUpdatedPartsList(ref batch); + + // Allow only recursive calls from the import engine to see the changes until + // they've been verified ... + using (var atomicComposition = new AtomicComposition()) + { + // Don't allow reentrant calls to compose during previewing to prevent + // corrupted state. + if (this._currentlyComposing) + { + throw new InvalidOperationException(Strings.ReentrantCompose); + } + + this._currentlyComposing = true; + + try + { + // In the meantime recursive calls need to be able to see the list as well + atomicComposition.SetValue(this, newParts); + + // Recompose any existing imports effected by the these changes first so that + // adapters, resurrected parts, etc. can all play their role in satisfying + // imports for added parts + this.Recompose(batch, atomicComposition); + + // Ensure that required imports can be satisfied + foreach (ComposablePart part in batch.PartsToAdd) + { + // collect the result of previewing all the adds in the batch + try + { + this.ImportEngine.PreviewImports(part, atomicComposition); + } + catch (ChangeRejectedException ex) + { + result = result.MergeResult(new CompositionResult(ex.Errors)); + } + } + + result.ThrowOnErrors(atomicComposition); + + // Complete the new parts since they passed previewing.` + using (this._lock.LockStateForWrite()) + { + this._parts = newParts; + } + + atomicComposition.Complete(); + } + finally + { + this._currentlyComposing = false; + } + } + + // Satisfy Imports + // - Satisfy imports on all newly added component parts + foreach (ComposablePart part in batch.PartsToAdd) + { + result = result.MergeResult(CompositionServices.TryInvoke(() => + this.ImportEngine.SatisfyImports(part))); + } + + // return errors + result.ThrowOnErrors(); + } + + private List<ComposablePart> GetUpdatedPartsList(ref CompositionBatch batch) + { + Assumes.NotNull(batch); + + // Copy the current list of parts - we are about to modify it + // This is an OK thing to do as this is the only method that can modify the List AND Compose can + // only be executed on one thread at a time - thus two different threads cannot tramp over each other + List<ComposablePart> parts = null; + using (this._lock.LockStateForRead()) + { + parts = this._parts.ToList(); // this copies the list + } + + foreach (ComposablePart part in batch.PartsToAdd) + { + parts.Add(part); + } + + List<ComposablePart> partsToRemove = null; + + foreach (ComposablePart part in batch.PartsToRemove) + { + if (parts.Remove(part)) + { + if (partsToRemove == null) + { + partsToRemove = new List<ComposablePart>(); + } + partsToRemove.Add(part); + } + } + + // Clone the batch, so that the external changes wouldn't happen half-way thorugh compose + // NOTE : this does not guarantee the atomicity of cloning, which is not the goal anyway, + // rather the fact that all subsequent calls will deal with an unchanging batch + batch = new CompositionBatch(batch.PartsToAdd, partsToRemove); + + return parts; + } + + private void Recompose(CompositionBatch batch, AtomicComposition atomicComposition) + { + Assumes.NotNull(batch); + + // Unregister any removed component parts + foreach (ComposablePart part in batch.PartsToRemove) + { + this.ImportEngine.ReleaseImports(part, atomicComposition); + } + + // Recompose any imports effected by the these changes (the changes are + // observable through GetExports in the appropriate atomicComposition, thus we can fire + // the event + IEnumerable<ExportDefinition> addedExports = batch.PartsToAdd.Count != 0 ? + batch.PartsToAdd.SelectMany(part => part.ExportDefinitions).ToArray() : + new ExportDefinition[0]; + + IEnumerable<ExportDefinition> removedExports = batch.PartsToRemove.Count != 0 ? + batch.PartsToRemove.SelectMany(part => part.ExportDefinitions).ToArray() : + new ExportDefinition[0]; + + this.OnExportsChanging( + new ExportsChangeEventArgs(addedExports, removedExports, atomicComposition)); + + atomicComposition.AddCompleteAction(() => this.OnExportsChanged( + new ExportsChangeEventArgs(addedExports, removedExports, null))); + } + + private Export CreateExport(ComposablePart part, ExportDefinition export) + { + return new Export(export, () => GetExportedValue(part, export)); + } + + private object GetExportedValue(ComposablePart part, ExportDefinition export) + { + this.ThrowIfDisposed(); + this.EnsureRunning(); + + return CompositionServices.GetExportedValueFromComposedPart(this.ImportEngine, part, export); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw new ObjectDisposedException(this.GetType().Name); + } + } + + [DebuggerStepThrough] + private void EnsureCanRun() + { + if (this._sourceProvider == null) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ObjectMustBeInitialized, "SourceProvider")); // NOLOC + } + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void EnsureRunning() + { + if (!this._isRunning) + { + using (this._lock.LockStateForWrite()) + { + if (!this._isRunning) + { + this.EnsureCanRun(); + this._isRunning = true; + } + } + } + } + + [DebuggerStepThrough] + private void EnsureCanSet<T>(T currentValue) + where T : class + { + if ((this._isRunning) || (currentValue != null)) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ObjectAlreadyInitialized)); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionBatch.SingleExportComposablePart.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionBatch.SingleExportComposablePart.cs new file mode 100644 index 00000000000..fd5875e5b40 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionBatch.SingleExportComposablePart.cs @@ -0,0 +1,62 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + partial class CompositionBatch + { + // Represents a part that exports a single export + private class SingleExportComposablePart : ComposablePart + { + private readonly Export _export; + + public SingleExportComposablePart(Export export) + { + Assumes.NotNull(export); + + this._export = export; + } + + public override IDictionary<string, object> Metadata + { + get { return MetadataServices.EmptyMetadata; } + } + + public override IEnumerable<ExportDefinition> ExportDefinitions + { + get { return new ExportDefinition[] { _export.Definition }; } + } + + public override IEnumerable<ImportDefinition> ImportDefinitions + { + get { return Enumerable.Empty<ImportDefinition>(); } + } + + public override object GetExportedValue(ExportDefinition definition) + { + Requires.NotNull(definition, "definition"); + + if (definition != _export.Definition) + { + throw ExceptionBuilder.CreateExportDefinitionNotOnThisComposablePart("definition"); + } + + return _export.Value; + } + + public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports) + { + Requires.NotNull(definition, "definition"); + Requires.NotNullOrNullElements(exports, "exports"); + + throw ExceptionBuilder.CreateImportDefinitionNotOnThisComposablePart("definition"); + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionBatch.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionBatch.cs new file mode 100644 index 00000000000..24be4db75dd --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionBatch.cs @@ -0,0 +1,178 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.Contracts; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CompositionBatch + { + private object _lock = new object(); + private bool _copyNeededForAdd; + private bool _copyNeededForRemove; + private List<ComposablePart> _partsToAdd; + private ReadOnlyCollection<ComposablePart> _readOnlyPartsToAdd; + private List<ComposablePart> _partsToRemove; + private ReadOnlyCollection<ComposablePart> _readOnlyPartsToRemove; + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionBatch"/> class. + /// </summary> + public CompositionBatch() : + this(null, null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionBatch"/> class. + /// </summary> + /// <param name="partsToAdd">The parts to add.</param> + /// <param name="partsToRemove">The parts to remove.</param> + public CompositionBatch(IEnumerable<ComposablePart> partsToAdd, IEnumerable<ComposablePart> partsToRemove) + { + this._partsToAdd = new List<ComposablePart>(); + if (partsToAdd != null) + { + foreach (var part in partsToAdd) + { + if (part == null) + { + throw ExceptionBuilder.CreateContainsNullElement("partsToAdd"); + } + this._partsToAdd.Add(part); + } + } + this._readOnlyPartsToAdd = this._partsToAdd.AsReadOnly(); + + this._partsToRemove = new List<ComposablePart>(); + if (partsToRemove != null) + { + foreach (var part in partsToRemove) + { + if (part == null) + { + throw ExceptionBuilder.CreateContainsNullElement("partsToRemove"); + } + this._partsToRemove.Add(part); + } + } + this._readOnlyPartsToRemove = this._partsToRemove.AsReadOnly(); + } + + /// <summary> + /// Returns the collection of parts that will be added. + /// </summary> + /// <value>The parts to be added.</value> + public ReadOnlyCollection<ComposablePart> PartsToAdd + { + get + { + Contract.Ensures(Contract.Result<ReadOnlyCollection<ComposablePart>>() != null); + + lock (this._lock) + { + this._copyNeededForAdd = true; + return this._readOnlyPartsToAdd; + } + } + } + + /// <summary> + /// Returns the collection of parts that will be removed. + /// </summary> + /// <value>The parts to be removed.</value> + public ReadOnlyCollection<ComposablePart> PartsToRemove + { + get + { + Contract.Ensures(Contract.Result <ReadOnlyCollection<ComposablePart>>() != null); + + lock (this._lock) + { + this._copyNeededForRemove = true; + return this._readOnlyPartsToRemove; + } + } + } + + /// <summary> + /// Adds the specified part to the <see cref="CompositionBatch"/>. + /// </summary> + /// <param name="part"> + /// The part. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="part"/> is <see langword="null"/>. + /// </exception> + public void AddPart(ComposablePart part) + { + Requires.NotNull(part, "part"); + lock (this._lock) + { + if (this._copyNeededForAdd) + { + this._partsToAdd = new List<ComposablePart>(this._partsToAdd); + this._readOnlyPartsToAdd = this._partsToAdd.AsReadOnly(); + this._copyNeededForAdd = false; + } + this._partsToAdd.Add(part); + } + } + + /// <summary> + /// Removes the specified part from the <see cref="CompositionBatch"/>. + /// </summary> + /// <param name="part"> + /// The part. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="part"/> is <see langword="null"/>. + /// </exception> + public void RemovePart(ComposablePart part) + { + Requires.NotNull(part, "part"); + lock (this._lock) + { + if (this._copyNeededForRemove) + { + this._partsToRemove = new List<ComposablePart>(this._partsToRemove); + this._readOnlyPartsToRemove = this._partsToRemove.AsReadOnly(); + this._copyNeededForRemove = false; + } + this._partsToRemove.Add(part); + } + } + + /// <summary> + /// Adds the specified export to the <see cref="CompositionBatch"/>. + /// </summary> + /// <param name="export"> + /// The <see cref="Export"/> to add to the <see cref="CompositionBatch"/>. + /// </param> + /// <returns> + /// A <see cref="ComposablePart"/> that can be used remove the <see cref="Export"/> + /// from the <see cref="CompositionBatch"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="export"/> is <see langword="null"/>. + /// </exception> + /// <remarks> + /// </remarks> + public ComposablePart AddExport(Export export) + { + Requires.NotNull(export, "export"); + Contract.Ensures(Contract.Result<ComposablePart>() != null); + + ComposablePart part = new SingleExportComposablePart(export); + + this.AddPart(part); + + return part; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionConstants.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionConstants.cs new file mode 100644 index 00000000000..aae9cfce7c3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionConstants.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.Hosting +{ + public static class CompositionConstants + { + private const string CompositionNamespace = "System.ComponentModel.Composition"; + + public const string PartCreationPolicyMetadataName = CompositionNamespace + ".CreationPolicy"; + public const string ImportSourceMetadataName = CompositionNamespace + ".ImportSource"; + public const string IsGenericPartMetadataName = CompositionNamespace + ".IsGenericPart"; + public const string GenericContractMetadataName = CompositionNamespace + ".GenericContractName"; + public const string GenericParametersMetadataName = CompositionNamespace + ".GenericParameters"; + public const string ExportTypeIdentityMetadataName = "ExportTypeIdentity"; + + internal const string GenericImportParametersOrderMetadataName = CompositionNamespace + ".GenericImportParametersOrderMetadataName"; + internal const string GenericExportParametersOrderMetadataName = CompositionNamespace + ".GenericExportParametersOrderMetadataName"; + internal const string GenericPartArityMetadataName = CompositionNamespace + ".GenericPartArity"; + internal const string GenericParameterConstraintsMetadataName = CompositionNamespace + ".GenericParameterConstraints"; + internal const string GenericParameterAttributesMetadataName = CompositionNamespace + ".GenericParameterAttributes"; + + internal const string ProductDefinitionMetadataName = "ProductDefinition"; + + internal const string PartCreatorContractName = CompositionNamespace + ".Contracts.ExportFactory"; + internal static readonly string PartCreatorTypeIdentity = AttributedModelServices.GetTypeIdentity(typeof(ComposablePartDefinition)); + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionContainer.CompositionServiceShim.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionContainer.CompositionServiceShim.cs new file mode 100644 index 00000000000..3d992138d92 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionContainer.CompositionServiceShim.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Text; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CompositionContainer + { + private class CompositionServiceShim : ICompositionService + { + CompositionContainer _innerContainer = null; + + public CompositionServiceShim(CompositionContainer innerContainer) + { + Assumes.NotNull(innerContainer); + this._innerContainer = innerContainer; + } + + void ICompositionService.SatisfyImportsOnce(ComposablePart part) + { + this._innerContainer.SatisfyImportsOnce(part); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionContainer.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionContainer.cs new file mode 100644 index 00000000000..9ac01dcb215 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionContainer.cs @@ -0,0 +1,589 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class CompositionContainer : ExportProvider, ICompositionService, IDisposable + { + private CompositionOptions _compositionOptions; + private ImportEngine _importEngine; + private ComposablePartExportProvider _partExportProvider; + private ExportProvider _rootProvider; + private CatalogExportProvider _catalogExportProvider; + + private AggregateExportProvider _localExportProvider; + private AggregateExportProvider _ancestorExportProvider; + + private readonly ReadOnlyCollection<ExportProvider> _providers; + private volatile bool _isDisposed = false; + private object _lock = new object(); + private static ReadOnlyCollection<ExportProvider> EmptyProviders = new ReadOnlyCollection<ExportProvider>(new ExportProvider[]{}); + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContainer"/> class. + /// </summary> + public CompositionContainer() + : this((ComposablePartCatalog)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContainer"/> class + /// with the specified export providers. + /// </summary> + /// <param name="providers"> + /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide + /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, + /// or <see langword="null"/> to set <see cref="Providers"/> to an empty + /// <see cref="ReadOnlyCollection{T}"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="providers"/> contains an element that is <see langword="null"/>. + /// </exception> + public CompositionContainer(params ExportProvider[] providers) : + this((ComposablePartCatalog)null, providers) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContainer"/> class + /// with the specified export providers. + /// </summary> + /// <param name="compositionOPtionss"> + /// <see cref="CompositionOptions"/> enumeration with flags controlling the composition. + /// </param> + /// <param name="providers"> + /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide + /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, + /// or <see langword="null"/> to set <see cref="Providers"/> to an empty + /// <see cref="ReadOnlyCollection{T}"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="providers"/> contains an element that is <see langword="null"/>. + /// </exception> + public CompositionContainer(CompositionOptions compositionOptions, params ExportProvider[] providers) : + this((ComposablePartCatalog)null, compositionOptions, providers) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContainer"/> class + /// with the specified catalog and export providers. + /// </summary> + /// <param name="providers"> + /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide + /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, + /// or <see langword="null"/> to set <see cref="Providers"/> to an empty + /// <see cref="ReadOnlyCollection{T}"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="providers"/> contains an element that is <see langword="null"/>. + /// </exception> + public CompositionContainer(ComposablePartCatalog catalog, params ExportProvider[] providers): + this(catalog, false, providers) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContainer"/> class + /// with the specified catalog and export providers. + /// </summary> + /// <param name="isThreadSafe"> + /// <see cref="bool"/> indicates whether container instances are threadsafe. + /// </param> + /// <param name="providers"> + /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide + /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, + /// or <see langword="null"/> to set <see cref="Providers"/> to an empty + /// <see cref="ReadOnlyCollection{T}"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="providers"/> contains an element that is <see langword="null"/>. + /// </exception> + public CompositionContainer(ComposablePartCatalog catalog, bool isThreadSafe, params ExportProvider[] providers) + : this(catalog, isThreadSafe ? CompositionOptions.IsThreadSafe : CompositionOptions.Default, providers) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionContainer"/> class + /// with the specified catalog and export providers. + /// </summary> + /// <param name="compositionSettings"> + /// <see cref="CompositionOptions"/> enumeration with flags controlling the composition. + /// </param> + /// <param name="providers"> + /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide + /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, + /// or <see langword="null"/> to set <see cref="Providers"/> to an empty + /// <see cref="ReadOnlyCollection{T}"/>. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="providers"/> contains an element that is <see langword="null"/>. + /// </exception> + public CompositionContainer(ComposablePartCatalog catalog, CompositionOptions compositionOptions, params ExportProvider[] providers) + { + if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) + { + throw new ArgumentOutOfRangeException("compositionOptions"); + } + this._compositionOptions = compositionOptions; + + this._partExportProvider = new ComposablePartExportProvider(compositionOptions); + this._partExportProvider.SourceProvider = this; + + bool multiProvider = (catalog != null) || providers.Length > 0; + + if (multiProvider) + { + if (catalog != null) + { + this._catalogExportProvider = new CatalogExportProvider(catalog, compositionOptions); + this._catalogExportProvider.SourceProvider = this; + this._localExportProvider = new AggregateExportProvider(this._partExportProvider, this._catalogExportProvider); + } + else + { + this._localExportProvider = new AggregateExportProvider(this._partExportProvider); + } + if(providers != null && providers.Length > 0) + { + this._ancestorExportProvider = new AggregateExportProvider(providers); + this._rootProvider = new AggregateExportProvider(this._localExportProvider, this._ancestorExportProvider); + } + else + { + this._rootProvider = this._localExportProvider; + } + } + else + { + this._rootProvider = this._partExportProvider; + } + + //Insert Composition Service + if(compositionOptions.HasFlag(CompositionOptions.ExportCompositionService)) + { + this.ComposeExportedValue<ICompositionService>(new CompositionServiceShim(this)); + } + + this._rootProvider.ExportsChanged += this.OnExportsChangedInternal; + this._rootProvider.ExportsChanging += this.OnExportsChangingInternal; + + this._providers = (providers != null) ? new ReadOnlyCollection<ExportProvider>((ExportProvider[])providers.Clone()) : EmptyProviders; + } + + internal CompositionOptions CompositionOptions + { + get + { + this.ThrowIfDisposed(); + return _compositionOptions; + } + } + + /// <summary> + /// Gets the catalog which provides the container access to exports produced + /// from composable parts. + /// </summary> + /// <value> + /// The <see cref="ComposablePartCatalog"/> which provides the + /// <see cref="CompositionContainer"/> access to exports produced from + /// <see cref="ComposablePart"/> objects. The default is <see langword="null"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public ComposablePartCatalog Catalog + { + get + { + this.ThrowIfDisposed(); + + return (this._catalogExportProvider != null) ? this._catalogExportProvider.Catalog : null; + } + } + + internal CatalogExportProvider CatalogExportProvider + { + get + { + this.ThrowIfDisposed(); + + return this._catalogExportProvider; + } + } + + /// <summary> + /// Gets the export providers which provide the container access to additional exports. + /// </summary> + /// <value> + /// A <see cref="ReadOnlyCollection{T}"/> of <see cref="ExportProvider"/> objects + /// which provide the <see cref="CompositionContainer"/> access to additional + /// <see cref="Export"/> objects. The default is an empty + /// <see cref="ReadOnlyCollection{T}"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public ReadOnlyCollection<ExportProvider> Providers + { + get + { + this.ThrowIfDisposed(); + Contract.Ensures(Contract.Result<ReadOnlyCollection<ExportProvider>>() != null); + + return this._providers; + } + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (!this._isDisposed) + { + ExportProvider rootProvider = null; + AggregateExportProvider ancestorExportProvider = null; + AggregateExportProvider localExportProvider = null; + ComposablePartExportProvider partExportProvider = null; + CatalogExportProvider catalogExportProvider = null; + ImportEngine importEngine = null; + + lock(this._lock) + { + if (!this._isDisposed) + { + rootProvider = this._rootProvider; + this._rootProvider = null; + + localExportProvider = this._localExportProvider; + this._localExportProvider = null; + + ancestorExportProvider = this._ancestorExportProvider; + this._ancestorExportProvider = null; + + partExportProvider = this._partExportProvider; + this._partExportProvider = null; + + catalogExportProvider = this._catalogExportProvider; + this._catalogExportProvider = null; + + importEngine = this._importEngine; + this._importEngine = null; + + this._isDisposed = true; + } + } + + if (rootProvider != null) + { + rootProvider.ExportsChanged -= this.OnExportsChangedInternal; + rootProvider.ExportsChanging -= this.OnExportsChangingInternal; + } + + if (ancestorExportProvider != null) + { + ancestorExportProvider.Dispose(); + } + + if (localExportProvider != null) + { + localExportProvider.Dispose(); + } + + if (catalogExportProvider != null) + { + catalogExportProvider.Dispose(); + } + + if (partExportProvider != null) + { + partExportProvider.Dispose(); + } + + if (importEngine != null) + { + importEngine.Dispose(); + } + } + + } + } + + public void Compose(CompositionBatch batch) + { + Requires.NotNull(batch, "batch"); + this.ThrowIfDisposed(); + + this._partExportProvider.Compose(batch); + } + + /// <summary> + /// Releases the <see cref="Export"/> from the <see cref="CompositionContainer"/>. The behavior + /// may vary depending on the implementation of the <see cref="ExportProvider"/> that produced + /// the <see cref="Export"/> instance. As a general rule non shared exports should be early + /// released causing them to be detached from the container. + /// + /// For example the <see cref="CatalogExportProvider"/> will only release + /// an <see cref="Export"/> if it comes from a <see cref="ComposablePart"/> that was constructed + /// under a <see cref="CreationPolicy.NonShared" /> context. Release in this context means walking + /// the dependency chain of the <see cref="Export"/>s, detaching references from the container and + /// calling Dispose on the <see cref="ComposablePart"/>s as needed. If the <see cref="Export"/> + /// was constructed under a <see cref="CreationPolicy.Shared" /> context the + /// <see cref="CatalogExportProvider"/> will do nothing as it may be in use by other requestors. + /// Those will only be detached when the container is itself disposed. + /// </summary> + /// <param name="export"><see cref="Export"/> that needs to be released.</param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="export"/> is <see langword="null"/>. + /// </exception> + [SuppressMessage("Microsoft.Performance", "CA1822")] + public void ReleaseExport(Export export) + { + Requires.NotNull(export, "export"); + + IDisposable dependency = export as IDisposable; + + if (dependency != null) + { + dependency.Dispose(); + } + } + + /// <summary> + /// Releases the <see cref="Lazy{T}"/> from the <see cref="CompositionContainer"/>. The behavior + /// may vary depending on the implementation of the <see cref="ExportProvider"/> that produced + /// the <see cref="Export"/> instance. As a general rule non shared exports should be early + /// released causing them to be detached from the container. + /// + /// For example the <see cref="CatalogExportProvider"/> will only release + /// an <see cref="Lazy{T}"/> if it comes from a <see cref="ComposablePart"/> that was constructed + /// under a <see cref="CreationPolicy.NonShared" /> context. Release in this context means walking + /// the dependency chain of the <see cref="Export"/>s, detaching references from the container and + /// calling Dispose on the <see cref="ComposablePart"/>s as needed. If the <see cref="Export"/> + /// was constructed under a <see cref="CreationPolicy.Shared" /> context the + /// <see cref="CatalogExportProvider"/> will do nothing as it may be in use by other requestors. + /// Those will only be detached when the container is itself disposed. + /// </summary> + /// <param name="export"><see cref="Export"/> that needs to be released.</param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="export"/> is <see langword="null"/>. + /// </exception> + [SuppressMessage("Microsoft.Performance", "CA1822")] + public void ReleaseExport<T>(Lazy<T> export) + { + Requires.NotNull(export, "export"); + + IDisposable dependency = export as IDisposable; + + if (dependency != null) + { + dependency.Dispose(); + } + } + + /// <summary> + /// Releases a set of <see cref="Export"/>s from the <see cref="CompositionContainer"/>. + /// See also <see cref="ReleaseExport"/>. + /// </summary> + /// <param name="exports"><see cref="Export"/>s that need to be released.</param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="exports"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="exports"/> contains an element that is <see langword="null"/>. + /// </exception> + public void ReleaseExports(IEnumerable<Export> exports) + { + Requires.NotNullOrNullElements(exports, "exports"); + + foreach (Export export in exports) + { + this.ReleaseExport(export); + } + } + + /// <summary> + /// Releases a set of <see cref="Export"/>s from the <see cref="CompositionContainer"/>. + /// See also <see cref="ReleaseExport"/>. + /// </summary> + /// <param name="exports"><see cref="Export"/>s that need to be released.</param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="exports"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="exports"/> contains an element that is <see langword="null"/>. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public void ReleaseExports<T>(IEnumerable<Lazy<T>> exports) + { + Requires.NotNullOrNullElements(exports, "exports"); + + foreach (Lazy<T> export in exports) + { + this.ReleaseExport(export); + } + } + + /// <summary> + /// Releases a set of <see cref="Export"/>s from the <see cref="CompositionContainer"/>. + /// See also <see cref="ReleaseExport"/>. + /// </summary> + /// <param name="exports"><see cref="Export"/>s that need to be released.</param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="exports"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="exports"/> contains an element that is <see langword="null"/>. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public void ReleaseExports<T, TMetadataView>(IEnumerable<Lazy<T, TMetadataView>> exports) + { + Requires.NotNullOrNullElements(exports, "exports"); + + foreach (Lazy<T, TMetadataView> export in exports) + { + this.ReleaseExport(export); + } + } + + /// <summary> + /// Sets the imports of the specified composable part exactly once and they will not + /// ever be recomposed. + /// </summary> + /// <param name="part"> + /// The <see cref="ComposablePart"/> to set the imports. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="part"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ICompositionService"/> has been disposed of. + /// </exception> + public void SatisfyImportsOnce(ComposablePart part) + { + this.ThrowIfDisposed(); + + if (this._importEngine == null) + { + ImportEngine importEngine = new ImportEngine(this, this._compositionOptions); + + lock(this._lock) + { + if (this._importEngine == null) + { + Thread.MemoryBarrier(); + this._importEngine = importEngine; + importEngine = null; + } + } + if(importEngine != null) + { + importEngine.Dispose(); + } + } + this._importEngine.SatisfyImportsOnce(part); + } + + internal void OnExportsChangedInternal(object sender, ExportsChangeEventArgs e) + { + this.OnExportsChanged(e); + } + + internal void OnExportsChangingInternal(object sender, ExportsChangeEventArgs e) + { + this.OnExportsChanging(e); + } + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> to get.</param> + /// <returns></returns> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <remarks> + /// <note type="inheritinfo"> + /// The implementers should not treat the cardinality-related mismatches as errors, and are not + /// expected to throw exceptions in those cases. + /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, + /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. + /// </note> + /// </remarks> + protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + + IEnumerable<Export> exports = null; + + object source; + if(!definition.Metadata.TryGetValue(CompositionConstants.ImportSourceMetadataName, out source)) + { + source = ImportSource.Any; + } + + switch((ImportSource)source) + { + case ImportSource.Any: + Assumes.NotNull(this._rootProvider); + this._rootProvider.TryGetExports(definition, atomicComposition, out exports); + break; + case ImportSource.Local: + Assumes.NotNull(this._localExportProvider); + this._localExportProvider.TryGetExports(definition.RemoveImportSource(), atomicComposition, out exports); + break; + case ImportSource.NonLocal: + if(this._ancestorExportProvider != null) + { + this._ancestorExportProvider.TryGetExports(definition.RemoveImportSource(), atomicComposition, out exports); + } + break; + } + + return exports; + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs new file mode 100644 index 00000000000..4edf3974184 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs @@ -0,0 +1,153 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +#define SINGLETHREADEDLOCKENFORCEMENT +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Threading; + +namespace System.ComponentModel.Composition.Hosting +{ + // This a a lock class that needs to be held in order to perform any mutation of the parts/parts state in the composition + // Today's implementation relies on the AppDomain-wide re-entrant lock for changes on the composition, and a narrow lock for changes in + // the state of the specific ImportEngine + // Today we make several assumptions to ensure thread-safety: + // 1. Each composition doesn't change lock affinity + // 2. Every part of the system that updates the status of the parts (in our case ImportEngine) needs to hold the same wide - lock + // 3. State of the import engine that gets accessed outside of the wide lock needs to be accessed in the context of the narrow lock + // 4. Narrow lock CAN be taken inside the wide lock + // 5. Wide lock CANNOT be taken inside the narrow lock + // 6. No 3rd party code will EVER get called inside the narrow lock + // Sadly, this means that we WILL be calling 3rd party code under a lock, but as long as the lock is re-entrant and they can't invoke us on anotehr thread + // we have no issue, other than potential overlocking + internal sealed class CompositionLock : IDisposable + { + // narrow lock + private readonly Lock _stateLock = null; + // wide lock + private static object _compositionLock = new object(); + + private int _isDisposed = 0; + private bool _isThreadSafe = false; + + private static readonly EmptyLockHolder _EmptyLockHolder = new EmptyLockHolder(); + + public CompositionLock(bool isThreadSafe) + { + this._isThreadSafe = isThreadSafe; + if (isThreadSafe) + { + this._stateLock = new Lock(); + } + } + + public void Dispose() + { + if (this._isThreadSafe) + { + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) + { + this._stateLock.Dispose(); + } + } + } + + public bool IsThreadSafe + { + get + { + return this._isThreadSafe; + } + } + + private void EnterCompositionLock() + { +#pragma warning disable 618 + if (this._isThreadSafe) + { + Monitor.Enter(_compositionLock); + } +#pragma warning restore 618 + } + + private void ExitCompositionLock() + { + if (this._isThreadSafe) + { + Monitor.Exit(_compositionLock); + } + } + + public IDisposable LockComposition() + { + if (this._isThreadSafe) + { + return new CompositionLockHolder(this); + } + else + { + return _EmptyLockHolder; + } + } + + public IDisposable LockStateForRead() + { + if (this._isThreadSafe) + { + return new ReadLock(this._stateLock); + } + else + { + return _EmptyLockHolder; + } + } + + public IDisposable LockStateForWrite() + { + if (this._isThreadSafe) + { + return new WriteLock(this._stateLock); + } + else + { + return _EmptyLockHolder; + } + } + + // NOTE : this should NOT be changed to a struct as ImportEngine relies on it + public sealed class CompositionLockHolder : IDisposable + { + private CompositionLock _lock; + private int _isDisposed; + + public CompositionLockHolder(CompositionLock @lock) + { + this._lock = @lock; + + this._isDisposed = 0; + this._lock.EnterCompositionLock(); + } + + public void Dispose() + { + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) + { + this._lock.ExitCompositionLock(); + } + } + } + + private sealed class EmptyLockHolder : IDisposable + { + public void Dispose() + { + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionOptions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionOptions.cs new file mode 100644 index 00000000000..fee5081accb --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionOptions.cs @@ -0,0 +1,21 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// Defines the Constructor settings for export providers. + /// </summary> + [Flags] + public enum CompositionOptions + { + Default = 0x0000, + DisableSilentRejection = 0x0001, + IsThreadSafe = 0x0002, + ExportCompositionService = 0x0004 + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionScopeDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionScopeDefinition.cs new file mode 100644 index 00000000000..382b2dee417 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionScopeDefinition.cs @@ -0,0 +1,276 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Linq; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.ComponentModel.Composition.Hosting; +using Microsoft.Internal; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.ComponentModel.Composition.ReflectionModel; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.Hosting +{ + [DebuggerTypeProxy(typeof(CompositionScopeDefinitionDebuggerProxy))] + public class CompositionScopeDefinition : ComposablePartCatalog, INotifyComposablePartCatalogChanged + { + private ComposablePartCatalog _catalog; + private IEnumerable<ExportDefinition> _publicSurface = null; + private IEnumerable<CompositionScopeDefinition> _children = Enumerable.Empty<CompositionScopeDefinition>(); + private volatile int _isDisposed = 0; + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. + /// </summary> + protected CompositionScopeDefinition() { } + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. + /// </summary> + /// <param name="catalog">The catalog.</param> + /// <param name="children">The children.</param> + public CompositionScopeDefinition(ComposablePartCatalog catalog, IEnumerable<CompositionScopeDefinition> children) + { + Requires.NotNull(catalog, "catalog"); + Requires.NullOrNotNullElements(children, "children"); + + InitializeCompositionScopeDefinition(catalog, children, null); + } + + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. + /// </summary> + /// <param name="catalog">The catalog.</param> + /// <param name="children">The children.</param> + /// <param name="publicSurface">The exports that can be used to create new scopes.</param> + public CompositionScopeDefinition(ComposablePartCatalog catalog, IEnumerable<CompositionScopeDefinition> children, IEnumerable<ExportDefinition> publicSurface) + { + Requires.NotNull(catalog, "catalog"); + Requires.NullOrNotNullElements(children, "children"); + Requires.NullOrNotNullElements(publicSurface, "publicSurface"); + + InitializeCompositionScopeDefinition(catalog, children, publicSurface); + } + + + /// <summary> + /// Initializes a new instance of the <see cref="CompositionScopeDefinition"/> class. + /// </summary> + /// <param name="catalog">The catalog.</param> + /// <param name="children">The children.</param> + private void InitializeCompositionScopeDefinition(ComposablePartCatalog catalog, IEnumerable<CompositionScopeDefinition> children, IEnumerable<ExportDefinition> publicSurface) + { + this._catalog = catalog; + if (children != null) + { + this._children = children.ToArray(); + } + if(publicSurface != null) + { + this._publicSurface = publicSurface; + } + + INotifyComposablePartCatalogChanged notifyCatalog = this._catalog as INotifyComposablePartCatalogChanged; + if (notifyCatalog != null) + { + notifyCatalog.Changed += this.OnChangedInternal; + notifyCatalog.Changing += this.OnChangingInternal; + } + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. +#pragma warning disable 420 + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) +#pragma warning restore 420 + { + INotifyComposablePartCatalogChanged notifyCatalog = this._catalog as INotifyComposablePartCatalogChanged; + if (notifyCatalog != null) + { + notifyCatalog.Changed -= this.OnChangedInternal; + notifyCatalog.Changing -= this.OnChangingInternal; + } + } + } + } + finally + { + base.Dispose(disposing); + } + } + + /// <summary> + /// Gets the children. + /// </summary> + /// <value>The children.</value> + public virtual IEnumerable<CompositionScopeDefinition> Children + { + get + { + this.ThrowIfDisposed(); + + return this._children; + } + } + + /// <summary> + /// Gets the export definitions that describe the exports surfaced by the CompositionScopedefinition. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/> objects describing + /// the exports surfaced by the <see cref="CompositionScopeDefinition"/>. + /// </value> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property must not return <see langword="null"/>. + /// </note> + /// </remarks> + public virtual IEnumerable<ExportDefinition> PublicSurface + { + get + { + this.ThrowIfDisposed(); + if(this._publicSurface == null) + { + return this.SelectMany( (p) => p.ExportDefinitions ); + } + + return this._publicSurface; + } + } + + /// <summary> + /// Gets an Enumerator for the ComposablePartDefinitions + /// </summary> + /// <value>The children.</value> + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + return this._catalog.GetEnumerator(); + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return.</param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePartCatalog"/> has been disposed of. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>, if no + /// <see cref="ExportDefinition"/> match the conditions defined by + /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>. + /// </note> + /// </remarks> + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + this.ThrowIfDisposed(); + + return this._catalog.GetExports(definition); + } + + internal IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExportsFromPublicSurface(ImportDefinition definition) + { + Assumes.NotNull(definition, "definition"); + + var exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); + + foreach(var exportDefinition in this.PublicSurface) + { + if (definition.IsConstraintSatisfiedBy(exportDefinition)) + { + foreach (var export in this.GetExports(definition)) + { + if(export.Item2 == exportDefinition) + { + exports.Add(export); + break; + } + } + } + } + return exports; + } + + /// <summary> + /// Notify when the contents of the Catalog has changed. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed; + + /// <summary> + /// Notify when the contents of the Catalog is changing. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing; + + /// <summary> + /// Raises the <see cref="E:Changed"/> event. + /// </summary> + /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param> + protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e) + { + EventHandler<ComposablePartCatalogChangeEventArgs> changedEvent = this.Changed; + if (changedEvent != null) + { + changedEvent.Invoke(this, e); + } + } + + /// <summary> + /// Raises the <see cref="E:Changing"/> event. + /// </summary> + /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param> + protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e) + { + EventHandler<ComposablePartCatalogChangeEventArgs> changingEvent = this.Changing; + if (changingEvent != null) + { + changingEvent.Invoke(this, e); + } + } + + private void OnChangedInternal(object sender, ComposablePartCatalogChangeEventArgs e) + { + this.OnChanged(e); + } + + private void OnChangingInternal(object sender, ComposablePartCatalogChangeEventArgs e) + { + this.OnChanging(e); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed == 1) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionScopeDefinitionDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionScopeDefinitionDebuggerProxy.cs new file mode 100644 index 00000000000..c0d75a65075 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionScopeDefinitionDebuggerProxy.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.Hosting +{ + // This proxy is needed to pretty up CompositionScopeDefinitionCatalog.Parts; IQueryable<T> + // instances are not displayed in a very friendly way in the debugger. + internal class CompositionScopeDefinitionDebuggerProxy + { + private readonly CompositionScopeDefinition _compositionScopeDefinition; + + public CompositionScopeDefinitionDebuggerProxy(CompositionScopeDefinition compositionScopeDefinition) + { + Requires.NotNull(compositionScopeDefinition, "compositionScopeDefinition"); + + this._compositionScopeDefinition = compositionScopeDefinition; + } + + public ReadOnlyCollection<ComposablePartDefinition> Parts + { + get { return this._compositionScopeDefinition.Parts.ToReadOnlyCollection(); } + } + + public IEnumerable<ExportDefinition> PublicSurface + { + get + { + return this._compositionScopeDefinition.PublicSurface.ToReadOnlyCollection(); + } + } + + public virtual IEnumerable<CompositionScopeDefinition> Children + { + get + { + return this._compositionScopeDefinition.Children.ToReadOnlyCollection(); + } + } + + + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionService.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionService.cs new file mode 100644 index 00000000000..4e83bb83b5f --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionService.cs @@ -0,0 +1,73 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// A mutable collection of <see cref="ComposablePartCatalog"/>s. + /// </summary> + /// <remarks> + /// This type is thread safe. + /// </remarks> + public class CompositionService : ICompositionService, IDisposable + { + private CompositionContainer _compositionContainer = null; + private INotifyComposablePartCatalogChanged _notifyCatalog = null; + + internal CompositionService(ComposablePartCatalog composablePartCatalog) + { + Assumes.NotNull(composablePartCatalog); + this._notifyCatalog = composablePartCatalog as INotifyComposablePartCatalogChanged; + try + { + if(this._notifyCatalog != null) + { + this._notifyCatalog.Changing += this.OnCatalogChanging; + } + + var compositionOptions = CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService; + var compositionContainer = new CompositionContainer(composablePartCatalog, compositionOptions); + + this._compositionContainer = compositionContainer; + } + catch + { + if(this._notifyCatalog != null) + { + this._notifyCatalog.Changing -= this.OnCatalogChanging; + } + throw; + } + } + + public void SatisfyImportsOnce(ComposablePart part) + { + Requires.NotNull(part, "part"); + Assumes.NotNull(this._compositionContainer); + this._compositionContainer.SatisfyImportsOnce(part); + } + + public void Dispose() + { + Assumes.NotNull(this._compositionContainer); + + // Delegates are cool there is no concern if you try to remove an item from them and they don't exist + if (this._notifyCatalog != null) + { + this._notifyCatalog.Changing -= this.OnCatalogChanging; + } + this._compositionContainer.Dispose(); + } + + private void OnCatalogChanging(object sender, ComposablePartCatalogChangeEventArgs e) + { + throw new ChangeRejectedException(Strings.NotSupportedCatalogChanges); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionServices.cs new file mode 100644 index 00000000000..a68f8639ebe --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionServices.cs @@ -0,0 +1,662 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.AttributedModel; +using System.ComponentModel.Composition.Primitives; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.ReflectionModel; + +namespace System.ComponentModel.Composition.Hosting +{ + internal static class CompositionServices + { + internal static readonly Type InheritedExportAttributeType = typeof(InheritedExportAttribute); + internal static readonly Type ExportAttributeType = typeof(ExportAttribute); + internal static readonly Type AttributeType = typeof(Attribute); + internal static readonly Type ObjectType = typeof(object); + + private static readonly string[] reservedMetadataNames = new string[] + { + CompositionConstants.PartCreationPolicyMetadataName + }; + + internal static Type GetDefaultTypeFromMember(this MemberInfo member) + { + Assumes.NotNull(member); + + switch (member.MemberType) + { + case MemberTypes.Property: + return ((PropertyInfo)member).PropertyType; + + case MemberTypes.NestedType: + case MemberTypes.TypeInfo: + return ((Type)member); + + case MemberTypes.Field: + default: + Assumes.IsTrue(member.MemberType == MemberTypes.Field); + return ((FieldInfo)member).FieldType; + } + } + + internal static Type AdjustSpecifiedTypeIdentityType(this Type specifiedContractType, MemberInfo member) + { + if (member.MemberType == MemberTypes.Method) + { + return specifiedContractType; + } + else + { + return specifiedContractType.AdjustSpecifiedTypeIdentityType(member.GetDefaultTypeFromMember()); + } + } + + internal static Type AdjustSpecifiedTypeIdentityType(this Type specifiedContractType, Type memberType) + { + Assumes.NotNull(specifiedContractType); + + if ((memberType != null) && memberType.IsGenericType && specifiedContractType.IsGenericType) + { + // if the memeber type is closed and the specified contract type is open and they have exatly the same number of parameters + // we will close the specfied contract type + if (specifiedContractType.ContainsGenericParameters && !memberType.ContainsGenericParameters) + { + var typeGenericArguments = memberType.GetGenericArguments(); + var metadataTypeGenericArguments = specifiedContractType.GetGenericArguments(); + + if (typeGenericArguments.Length == metadataTypeGenericArguments.Length) + { + return specifiedContractType.MakeGenericType(typeGenericArguments); + } + } + // if both member type and the contract type are open generic types, make sure that their parameters are ordered the same way + else if(specifiedContractType.ContainsGenericParameters && memberType.ContainsGenericParameters) + { + var memberGenericParameters = memberType.GetPureGenericParameters(); + if (specifiedContractType.GetPureGenericArity() == memberGenericParameters.Count) + { + return specifiedContractType.GetGenericTypeDefinition().MakeGenericType(memberGenericParameters.ToArray()); + } + } + } + + return specifiedContractType; + } + + private static string AdjustTypeIdentity(string originalTypeIdentity, Type typeIdentityType) + { + return GenericServices.GetGenericName(originalTypeIdentity, GenericServices.GetGenericParametersOrder(typeIdentityType), GenericServices.GetPureGenericArity(typeIdentityType)); + } + + internal static void GetContractInfoFromExport(this MemberInfo member, ExportAttribute export, out Type typeIdentityType, out string contractName) + { + typeIdentityType = member.GetTypeIdentityTypeFromExport(export); + if (!string.IsNullOrEmpty(export.ContractName)) + { + contractName = export.ContractName; + } + else + { + contractName = member.GetTypeIdentityFromExport(typeIdentityType); + } + } + + + internal static string GetTypeIdentityFromExport(this MemberInfo member, Type typeIdentityType) + { + if (typeIdentityType != null) + { + string typeIdentity = AttributedModelServices.GetTypeIdentity(typeIdentityType); + if (typeIdentityType.ContainsGenericParameters) + { + typeIdentity = AdjustTypeIdentity(typeIdentity, typeIdentityType); + } + return typeIdentity; + } + else + { + MethodInfo method = member as MethodInfo; + Assumes.NotNull(method); + return AttributedModelServices.GetTypeIdentity(method); + } + } + + private static Type GetTypeIdentityTypeFromExport(this MemberInfo member, ExportAttribute export) + { + if (export.ContractType != null) + { + return export.ContractType.AdjustSpecifiedTypeIdentityType(member); + } + else + { + return (member.MemberType != MemberTypes.Method) ? member.GetDefaultTypeFromMember() : null; + } + } + + internal static bool IsContractNameSameAsTypeIdentity(this ExportAttribute export) + { + return string.IsNullOrEmpty(export.ContractName); + } + + + internal static Type GetContractTypeFromImport(this IAttributedImport import, ImportType importType) + { + if (import.ContractType != null) + { + return import.ContractType.AdjustSpecifiedTypeIdentityType(importType.ContractType); + } + + return importType.ContractType; + } + + internal static string GetContractNameFromImport(this IAttributedImport import, ImportType importType) + { + if (!string.IsNullOrEmpty(import.ContractName)) + { + return import.ContractName; + } + + Type contractType = import.GetContractTypeFromImport(importType); + + return AttributedModelServices.GetContractName(contractType); + } + + internal static string GetTypeIdentityFromImport(this IAttributedImport import, ImportType importType) + { + Type contractType = import.GetContractTypeFromImport(importType); + + // For our importers we treat object as not having a type identity + if (contractType == CompositionServices.ObjectType) + { + return null; + } + + return AttributedModelServices.GetTypeIdentity(contractType); + } + + internal static IDictionary<string, object> GetPartMetadataForType(this Type type, CreationPolicy creationPolicy) + { + IDictionary<string, object> dictionary = new Dictionary<string, object>(StringComparers.MetadataKeyNames); + + if (creationPolicy != CreationPolicy.Any) + { + dictionary.Add(CompositionConstants.PartCreationPolicyMetadataName, creationPolicy); + } + + foreach (PartMetadataAttribute partMetadata in type.GetAttributes<PartMetadataAttribute>()) + { + if (reservedMetadataNames.Contains(partMetadata.Name, StringComparers.MetadataKeyNames) + || dictionary.ContainsKey(partMetadata.Name)) + { + // Perhaps we should log an error here so that people know this value is being ignored. + continue; + } + + dictionary.Add(partMetadata.Name, partMetadata.Value); + } + + // metadata for generic types + if (type.ContainsGenericParameters) + { + // Register the part as generic + dictionary.Add(CompositionConstants.IsGenericPartMetadataName, true); + + // Add arity + Type[] genericArguments = type.GetGenericArguments(); + dictionary.Add(CompositionConstants.GenericPartArityMetadataName, genericArguments.Length); + + // add constraints + bool hasConstraints = false; + object[] genericParameterConstraints = new object[genericArguments.Length]; + GenericParameterAttributes[] genericParameterAttributes = new GenericParameterAttributes[genericArguments.Length]; + for (int i=0; i< genericArguments.Length ; i++) + { + Type genericArgument = genericArguments[i]; + + Type[] constraints = genericArgument.GetGenericParameterConstraints(); + if (constraints.Length == 0) + { + constraints = null; + } + + GenericParameterAttributes attributes = genericArgument.GenericParameterAttributes; + + if ((constraints != null) || (attributes != GenericParameterAttributes.None)) + { + genericParameterConstraints[i] = constraints; + genericParameterAttributes[i] = attributes; + hasConstraints = true; + } + } + + if (hasConstraints) + { + dictionary.Add(CompositionConstants.GenericParameterConstraintsMetadataName, genericParameterConstraints); + dictionary.Add(CompositionConstants.GenericParameterAttributesMetadataName, genericParameterAttributes); + } + } + + if (dictionary.Count == 0) + { + return MetadataServices.EmptyMetadata; + } + else + { + return dictionary; + } + } + + internal static void TryExportMetadataForMember(this MemberInfo member, out IDictionary<string, object> dictionary) + { + dictionary = new Dictionary<string, object>(); + + foreach (var attr in member.GetAttributes<Attribute>()) + { + var provider = attr as ExportMetadataAttribute; + + if (provider != null) + { + if (reservedMetadataNames.Contains(provider.Name, StringComparers.MetadataKeyNames)) + { + throw ExceptionBuilder.CreateDiscoveryException(Strings.Discovery_ReservedMetadataNameUsed, member.GetDisplayName(), provider.Name); + } + + // we pass "null" for valueType which would make it inferred. We don;t have additional type information when metadata + // goes through the ExportMetadataAttribute path + if (!dictionary.TryContributeMetadataValue(provider.Name, provider.Value, null, provider.IsMultiple)) + { + throw ExceptionBuilder.CreateDiscoveryException(Strings.Discovery_DuplicateMetadataNameValues, member.GetDisplayName(), provider.Name); + } + } + else + { + Type attrType = attr.GetType(); + if ((attrType != CompositionServices.ExportAttributeType) && attrType.IsAttributeDefined<MetadataAttributeAttribute>(true)) + { + bool allowsMultiple = false; + AttributeUsageAttribute usage = attrType.GetFirstAttribute<AttributeUsageAttribute>(true); + + if (usage != null) + { + allowsMultiple = usage.AllowMultiple; + } + + foreach (PropertyInfo pi in attrType.GetProperties()) + { + if (pi.DeclaringType == CompositionServices.ExportAttributeType || pi.DeclaringType == CompositionServices.AttributeType) + { + // Don't contribute metadata properies from the base attribute types. + continue; + } + + if (reservedMetadataNames.Contains(pi.Name, StringComparers.MetadataKeyNames)) + { + throw ExceptionBuilder.CreateDiscoveryException(Strings.Discovery_ReservedMetadataNameUsed, member.GetDisplayName(), provider.Name); + } + + object value = pi.GetValue(attr, null); + + if (value != null && !IsValidAttributeType(value.GetType())) + { + throw ExceptionBuilder.CreateDiscoveryException(Strings.Discovery_MetadataContainsValueWithInvalidType, pi.GetDisplayName(), value.GetType().GetDisplayName()); + } + + if (!dictionary.TryContributeMetadataValue(pi.Name, value, pi.PropertyType, allowsMultiple)) + { + throw ExceptionBuilder.CreateDiscoveryException(Strings.Discovery_DuplicateMetadataNameValues, member.GetDisplayName(), pi.Name); + } + } + } + } + } + + // Need Keys.ToArray because we alter the dictionary in the loop + foreach (var key in dictionary.Keys.ToArray()) + { + var list = dictionary[key] as MetadataList; + if (list != null) + { + dictionary[key] = list.ToArray(); + } + } + + return; + } + + private static bool TryContributeMetadataValue(this IDictionary<string, object> dictionary, string name, object value, Type valueType, bool allowsMultiple) + { + object metadataValue; + if (!dictionary.TryGetValue(name, out metadataValue)) + { + if (allowsMultiple) + { + var list = new MetadataList(); + list.Add(value, valueType); + value = list; + } + + dictionary.Add(name, value); + } + else + { + var list = metadataValue as MetadataList; + if (!allowsMultiple || list == null) + { + // Either single value already found when should be multiple + // or a duplicate name already exists + dictionary.Remove(name); + return false; + } + + list.Add(value, valueType); + } + return true; + } + + private class MetadataList + { + private Type _arrayType = null; + private bool _containsNulls = false; + private static readonly Type ObjectType = typeof(object); + private static readonly Type TypeType = typeof(Type); + private Collection<object> _innerList = new Collection<object>(); + + public void Add(object item, Type itemType) + { + this._containsNulls |= (item == null); + + // if we've been passed typeof(object), we basically have no type inmformation + if (itemType == ObjectType) + { + itemType = null; + } + + // if we have no type information, get it from the item, if we can + if ((itemType == null) && (item != null)) + { + itemType = item.GetType(); + } + + // Types are special, because the are abstract classes, so if the item casts to Type, we assume System.Type + if (item is Type) + { + itemType = TypeType; + } + + // only try to call this if we got a meaningful type + if (itemType != null) + { + this.InferArrayType(itemType); + } + + this._innerList.Add(item); + } + + private void InferArrayType(Type itemType) + { + Assumes.NotNull(itemType); + + if (this._arrayType == null) + { + // this is the first typed element we've been given, it sets the type of the array + this._arrayType = itemType; + } + else + { + // if there's a disagreement on the array type, we flip to Object + // NOTE : we can try to do better in the future to find common base class, but given that we support very limited set of types + // in metadata right now, it's a moot point + if (this._arrayType != itemType) + { + this._arrayType = ObjectType; + } + } + } + + public Array ToArray() + { + if (this._arrayType == null) + { + // if the array type has not been set, assume Object + this._arrayType = ObjectType; + } + else if (this._containsNulls && this._arrayType.IsValueType) + { + // if the array type is a value type and we have seen nulls, then assume Object + this._arrayType = ObjectType; + } + + Array array = Array.CreateInstance(this._arrayType, this._innerList.Count); + + for(int i = 0; i < array.Length; i++) + { + array.SetValue(this._innerList[i], i); + } + return array; + } + } + + //UNDONE: Need to add these warnings somewhere...Dev10:472538 should address this. + //internal static CompositionResult MatchRequiredMetadata(this IDictionary<string, object> metadata, IEnumerable<string> requiredMetadata, string contractName) + //{ + // Assumes.IsTrue(metadata != null); + + // var result = CompositionResult.SucceededResult; + + // var missingMetadata = (requiredMetadata == null) ? null : requiredMetadata.Except<string>(metadata.Keys); + // if (missingMetadata != null && missingMetadata.Any()) + // { + // result = result.MergeIssue( + // CompositionError.CreateIssueAsWarning(CompositionErrorId.RequiredMetadataNotFound, + // Strings.RequiredMetadataNotFound, + // contractName, + // string.Join(", ", missingMetadata.ToArray()))); + + // return new CompositionResult(false, result.Issues); + // } + + // return result; + //} + + internal static IEnumerable<KeyValuePair<string, Type>> GetRequiredMetadata(Type metadataViewType) + { + if ((metadataViewType == null) || + ExportServices.IsDefaultMetadataViewType(metadataViewType) || + ExportServices.IsDictionaryConstructorViewType(metadataViewType) || + !metadataViewType.IsInterface) + { + return Enumerable.Empty<KeyValuePair<string, Type>>(); + } + + // A metadata view is required to be an Intrerface, and therefore only properties are allowed + List<PropertyInfo> properties = metadataViewType.GetAllProperties(). + Where(property => property.GetFirstAttribute<DefaultValueAttribute>() == null). + ToList(); + + // NOTE : this is a carefully found balance between eager and delay-evaluation - the properties are filtered once and upfront + // whereas the key/Type pairs are created every time. The latter is fine as KVPs are structs and as such copied on access regardless. + // This also allows us to avoid creation of List<KVP> which - at least according to FxCop - leads to isues with NGEN + return properties.Select(property => new KeyValuePair<string, Type>(property.Name, property.PropertyType)); + } + + internal static IDictionary<string, object> GetImportMetadata(ImportType importType, IAttributedImport attributedImport) + { + return GetImportMetadata(importType.ContractType, attributedImport); + } + + internal static IDictionary<string, object> GetImportMetadata(Type type, IAttributedImport attributedImport) + { + Dictionary<string, object> metadata = null; + + if (type.IsGenericType) + { + metadata = new Dictionary<string, object>(); + + if (type.ContainsGenericParameters) + { + metadata[CompositionConstants.GenericImportParametersOrderMetadataName] = GenericServices.GetGenericParametersOrder(type); + } + else + { + metadata[CompositionConstants.GenericContractMetadataName] = ContractNameServices.GetTypeIdentity(type.GetGenericTypeDefinition()); + metadata[CompositionConstants.GenericParametersMetadataName] = type.GetGenericArguments(); + } + } + + // Default value is ImportSource.Any + if(attributedImport != null && attributedImport.Source != ImportSource.Any) + { + if(metadata == null) + { + metadata = new Dictionary<string, object>(); + } + metadata[CompositionConstants.ImportSourceMetadataName] = attributedImport.Source; + } + + if(metadata != null) + { + return metadata.AsReadOnly(); + } + else + { + return MetadataServices.EmptyMetadata; + } + } + + internal static object GetExportedValueFromComposedPart(ImportEngine engine, ComposablePart part, ExportDefinition definition) + { + if (engine != null) + { + try + { + engine.SatisfyImports(part); + } + catch (CompositionException ex) + { + throw ExceptionBuilder.CreateCannotGetExportedValue(part, definition, ex); + } + } + + try + { + return part.GetExportedValue(definition); + } + catch (ComposablePartException ex) + { + throw ExceptionBuilder.CreateCannotGetExportedValue(part, definition, ex); + } + } + + internal static bool IsRecomposable(this ComposablePart part) + { + return part.ImportDefinitions.Any(import => import.IsRecomposable); + } + + internal static CompositionResult TryInvoke(Action action) + { + try + { + action(); + return CompositionResult.SucceededResult; + } + catch (CompositionException ex) + { + return new CompositionResult(ex.Errors); + } + } + + internal static CompositionResult TryFire<TEventArgs>(EventHandler<TEventArgs> _delegate, object sender, TEventArgs e) + where TEventArgs : EventArgs + { + CompositionResult result = CompositionResult.SucceededResult; + foreach (EventHandler<TEventArgs> _subscriber in _delegate.GetInvocationList()) + { + try + { + _subscriber.Invoke(sender, e); + } + catch (CompositionException ex) + { + result = result.MergeErrors(ex.Errors); + } + } + + return result; + } + + internal static CreationPolicy GetRequiredCreationPolicy(this ImportDefinition definition) + { + ContractBasedImportDefinition contractDefinition = definition as ContractBasedImportDefinition; + + if (contractDefinition != null) + { + return contractDefinition.RequiredCreationPolicy; + } + + return CreationPolicy.Any; + } + + /// <summary> + /// Returns a value indicating whether cardinality is + /// <see cref="ImportCardinality.ZeroOrOne"/> or + /// <see cref="ImportCardinality.ExactlyOne"/>. + /// </summary> + internal static bool IsAtMostOne(this ImportCardinality cardinality) + { + return cardinality == ImportCardinality.ZeroOrOne || cardinality == ImportCardinality.ExactlyOne; + } + + private static bool IsValidAttributeType(Type type) + { + return IsValidAttributeType(type, true); + } + + private static bool IsValidAttributeType(Type type, bool arrayAllowed) + { + Assumes.NotNull(type); + // Definitions of valid attribute type taken from C# 3.0 Specification section 17.1.3. + + // One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort. + if (type.IsPrimitive) + { + return true; + } + + if (type == typeof(string)) + { + return true; + } + + // An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility + if (type.IsEnum && type.IsVisible) + { + return true; + } + + if (typeof(Type).IsAssignableFrom(type)) + { + return true; + } + + // Single-dimensional arrays of the above types. + if (arrayAllowed && type.IsArray && + type.GetArrayRank() == 1 && + IsValidAttributeType(type.GetElementType(), false)) + { + return true; + } + + return false; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/DirectoryCatalog.DirectoryCatalogDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/DirectoryCatalog.DirectoryCatalogDebuggerProxy.cs new file mode 100644 index 00000000000..3535021128f --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/DirectoryCatalog.DirectoryCatalogDebuggerProxy.cs @@ -0,0 +1,77 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + partial class DirectoryCatalog + { + internal class DirectoryCatalogDebuggerProxy + { + private readonly DirectoryCatalog _catalog; + + public DirectoryCatalogDebuggerProxy(DirectoryCatalog catalog) + { + Requires.NotNull(catalog, "catalog"); + + this._catalog = catalog; + } + + public ReadOnlyCollection<Assembly> Assemblies + { + get + { + return this._catalog._assemblyCatalogs.Values.Select(catalog => catalog.Assembly) + .ToReadOnlyCollection(); + } + } + +#if FEATURE_REFLECTIONCONTEXT + public ReflectionContext ReflectionContext + { + get + { + return this._catalog._reflectionContext; + } + } +#endif //FEATURE_REFLECTIONCONTEXT + + public string SearchPattern + { + get { return this._catalog.SearchPattern; } + } + + public string Path + { + get { return this._catalog._path; } + } + + public string FullPath + { + get { return this._catalog._fullPath; } + } + + public ReadOnlyCollection<string> LoadedFiles + { + get { return this._catalog._loadedFiles; } + } + + public ReadOnlyCollection<ComposablePartDefinition> Parts + { + // NOTE: This shouldn't be cached, so that on every query of + // the current value of the underlying catalog is respected. + // We use ReadOnlyCollection as arrays do not have the + // appropriate debugger display attributes applied to them. + get { return this._catalog.Parts.ToReadOnlyCollection(); } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/DirectoryCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/DirectoryCatalog.cs new file mode 100644 index 00000000000..bb96f389126 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/DirectoryCatalog.cs @@ -0,0 +1,821 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Diagnostics; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using IOPath = System.IO.Path; + +namespace System.ComponentModel.Composition.Hosting +{ + [DebuggerTypeProxy(typeof(DirectoryCatalogDebuggerProxy))] + public partial class DirectoryCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged, ICompositionElement + { + private readonly Lock _thisLock = new Lock(); + private readonly ICompositionElement _definitionOrigin = null; + private ComposablePartCatalogCollection _catalogCollection; + private Dictionary<string, AssemblyCatalog> _assemblyCatalogs; + private volatile bool _isDisposed = false; + private string _path; + private string _fullPath; + private string _searchPattern; + private ReadOnlyCollection<string> _loadedFiles; + +#if FEATURE_REFLECTIONCONTEXT + private readonly ReflectionContext _reflectionContext = null; +#endif //FEATURE_REFLECTIONCONTEXT + + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the *.dll files + /// in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path) + : this(path, "*.dll") + { + } + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the *.dll files + /// in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/> or + /// <paramref name="reflectionContext"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, ReflectionContext reflectionContext) + : this(path, "*.dll", reflectionContext) + { + } +#endif //FEATURE_REFLECTIONCONTEXT + + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the *.dll files + /// in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/> or + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, ICompositionElement definitionOrigin) + : this(path, "*.dll", definitionOrigin) + { + } + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the given searchPattern + /// over the files in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space + /// does not contain a valid pattern. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/> or + /// <paramref name="reflectionContext"/> is <see langword="null"/> or + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, ReflectionContext reflectionContext, ICompositionElement definitionOrigin) + : this(path, "*.dll", reflectionContext, definitionOrigin) + { + } +#endif //FEATURE_REFLECTIONCONTEXT + + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the *.dll files + /// in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="searchPattern"> + /// Any valid searchPattern that <see cref="Directory.GetFiles(string, string)"/> will accept. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. Or <paramref name="searchPattern"/> + /// does not contain a valid pattern. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, string searchPattern) + { + Requires.NotNullOrEmpty(path, "path"); + Requires.NotNullOrEmpty(searchPattern, "searchPattern"); + + this._definitionOrigin = this; + this.Initialize(path, searchPattern); + } + + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the *.dll files + /// in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. Or <paramref name="searchPattern"/> + /// does not contain a valid pattern. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/>. + /// <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, string searchPattern, ICompositionElement definitionOrigin) + { + Requires.NotNullOrEmpty(path, "path"); + Requires.NotNullOrEmpty(searchPattern, "searchPattern"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + this._definitionOrigin = definitionOrigin; + this.Initialize(path, searchPattern); + } + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the given searchPattern + /// over the files in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="searchPattern"> + /// Any valid searchPattern that <see cref="Directory.GetFiles(string, string)"/> will accept. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. Or <paramref name="searchPattern"/> + /// does not contain a valid pattern. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/> + /// or <paramref name="searchPattern"/> is <see langword="null"/>. + /// or <paramref name="reflectionContext"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, string searchPattern, ReflectionContext reflectionContext) + { + Requires.NotNullOrEmpty(path, "path"); + Requires.NotNullOrEmpty(searchPattern, "searchPattern"); + Requires.NotNull(reflectionContext, "reflectionContext"); + + this._reflectionContext = reflectionContext; + this._definitionOrigin = this; + this.Initialize(path, searchPattern); + } + + /// <summary> + /// Creates a catalog of <see cref="ComposablePartDefinition"/>s based on all the given searchPattern + /// over the files in the given directory path. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <param name="path"> + /// Path to the directory to scan for assemblies to add to the catalog. + /// The path needs to be absolute or relative to <see cref="AppDomain.BaseDirectory"/> + /// </param> + /// <param name="searchPattern"> + /// Any valid searchPattern that <see cref="Directory.GetFiles(string, string)"/> will accept. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// If <paramref name="path"/> is a zero-length string, contains only white space, or + /// contains one or more implementation-specific invalid characters. Or <paramref name="searchPattern"/> + /// does not contain a valid pattern. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="path"/> is <see langword="null"/> + /// or <paramref name="searchPattern"/> is <see langword="null"/>. + /// or <paramref name="reflectionContext"/> is <see langword="null"/>. + /// or <paramref name="definitionOrigin"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="DirectoryNotFoundException"> + /// The specified <paramref name="path"/> is invalid (for example, it is on an unmapped drive). + /// </exception> + /// <exception cref="PathTooLongException"> + /// The specified <paramref name="path"/>, file name, or both exceed the system-defined maximum length. + /// For example, on Windows-based platforms, paths must be less than 248 characters and file names must + /// be less than 260 characters. + /// </exception> + /// <exception cref="UnauthorizedAccessException"> + /// The caller does not have the required permission. + /// </exception> + public DirectoryCatalog(string path, string searchPattern, ReflectionContext reflectionContext, ICompositionElement definitionOrigin) + { + Requires.NotNullOrEmpty(path, "path"); + Requires.NotNullOrEmpty(searchPattern, "searchPattern"); + Requires.NotNull(reflectionContext, "reflectionContext"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + this._reflectionContext = reflectionContext; + this._definitionOrigin = definitionOrigin; + this.Initialize(path, searchPattern); + } +#endif //FEATURE_REFLECTIONCONTEXT + + /// <summary> + /// Translated absolute path of the path passed into the constructor of <see cref="DirectoryCatalog"/>. + /// </summary> + public string FullPath + { + get + { + Contract.Ensures(Contract.Result<string>() != null); + + return this._fullPath; + } + } + + /// <summary> + /// Set of files that have currently been loaded into the catalog. + /// </summary> + public ReadOnlyCollection<string> LoadedFiles + { + get + { + Contract.Ensures(Contract.Result<ReadOnlyCollection<string>>() != null); + + using (new ReadLock(this._thisLock)) + { + return this._loadedFiles; + } + } + } + + /// <summary> + /// Path passed into the constructor of <see cref="DirectoryCatalog"/>. + /// </summary> + public string Path + { + get + { + Contract.Ensures(Contract.Result<string>() != null); + + return this._path; + } + } + + /// <summary> + /// SearchPattern passed into the constructor of <see cref="DirectoryCatalog"/>, or the default *.dll. + /// </summary> + public string SearchPattern + { + get + { + return this._searchPattern; + } + } + + /// <summary> + /// Notify when the contents of the Catalog has changed. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed; + + /// <summary> + /// Notify when the contents of the Catalog has changing. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing; + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + if (!this._isDisposed) + { + bool disposeLock = false; + ComposablePartCatalogCollection catalogs = null; + + try + { + using (new WriteLock(this._thisLock)) + { + if (!this._isDisposed) + { + disposeLock = true; + catalogs = this._catalogCollection; + this._catalogCollection = null; + this._assemblyCatalogs = null; + this._isDisposed = true; + } + } + } + finally + { + if (catalogs != null) + { + catalogs.Dispose(); + } + + if (disposeLock) + { + this._thisLock.Dispose(); + } + } + } + } + } + finally + { + base.Dispose(disposing); + } + } + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + return this._catalogCollection.SelectMany(catalog => catalog as IEnumerable<ComposablePartDefinition>).GetEnumerator(); + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="DirectoryCatalog"/> has been disposed of. + /// </exception> + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + this.ThrowIfDisposed(); + + Requires.NotNull(definition, "definition"); + + return this._catalogCollection.SelectMany(catalog => catalog.GetExports(definition)); + } + + /// <summary> + /// Raises the <see cref="INotifyComposablePartCatalogChanged.Changed"/> event. + /// </summary> + /// <param name="e"> + /// An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event. + /// </param> + protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e) + { + EventHandler<ComposablePartCatalogChangeEventArgs> changedEvent = this.Changed; + if (changedEvent != null) + { + changedEvent(this, e); + } + } + + /// <summary> + /// Raises the <see cref="INotifyComposablePartCatalogChanged.Changing"/> event. + /// </summary> + /// <param name="e"> + /// An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event. + /// </param> + protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e) + { + EventHandler<ComposablePartCatalogChangeEventArgs> changingEvent = this.Changing; + if (changingEvent != null) + { + changingEvent(this, e); + } + } + + /// <summary> + /// Refreshes the <see cref="ComposablePartDefinition"/>s with the latest files in the directory that match + /// the searchPattern. If any files have been added they will be added to the catalog and if any files were + /// removed they will be removed from the catalog. For files that have been removed keep in mind that the + /// assembly cannot be unloaded from the process so <see cref="ComposablePartDefinition"/>s for those files + /// will simply be removed from the catalog. + /// + /// Possible exceptions that can be thrown are any that <see cref="Directory.GetFiles(string, string)"/> or + /// <see cref="Assembly.Load(AssemblyName)"/> can throw. + /// </summary> + /// <exception cref="DirectoryNotFoundException"> + /// The specified path has been removed since object construction. + /// </exception> + public void Refresh() + { + this.ThrowIfDisposed(); + Assumes.NotNull(this._loadedFiles); + + List<Tuple<string, AssemblyCatalog>> catalogsToAdd; + List<Tuple<string, AssemblyCatalog>> catalogsToRemove; + ComposablePartDefinition[] addedDefinitions; + ComposablePartDefinition[] removedDefinitions; + object changeReferenceObject; + string[] afterFiles; + string[] beforeFiles; + + while (true) + { + afterFiles = this.GetFiles(); + + using (new ReadLock(this._thisLock)) + { + changeReferenceObject = this._loadedFiles; + beforeFiles = this._loadedFiles.ToArray(); + } + + this.DiffChanges(beforeFiles, afterFiles, out catalogsToAdd, out catalogsToRemove); + + // Don't go any further if there's no work to do + if (catalogsToAdd.Count == 0 && catalogsToRemove.Count == 0) + { + return; + } + + // Notify listeners to give them a preview before completeting the changes + addedDefinitions = catalogsToAdd + .SelectMany(cat => cat.Item2 as IEnumerable<ComposablePartDefinition>) + .ToArray<ComposablePartDefinition>(); + + removedDefinitions = catalogsToRemove + .SelectMany(cat => cat.Item2 as IEnumerable<ComposablePartDefinition>) + .ToArray<ComposablePartDefinition>(); + + using (var atomicComposition = new AtomicComposition()) + { + var changingArgs = new ComposablePartCatalogChangeEventArgs(addedDefinitions, removedDefinitions, atomicComposition); + this.OnChanging(changingArgs); + + // if the change went through then write the catalog changes + using (new WriteLock(this._thisLock)) + { + if (changeReferenceObject != this._loadedFiles) + { + // Someone updated the list while we were diffing so we need to try the diff again + continue; + } + + foreach (var catalogToAdd in catalogsToAdd) + { + this._assemblyCatalogs.Add(catalogToAdd.Item1, catalogToAdd.Item2); + this._catalogCollection.Add(catalogToAdd.Item2); + } + + foreach (var catalogToRemove in catalogsToRemove) + { + this._assemblyCatalogs.Remove(catalogToRemove.Item1); + this._catalogCollection.Remove(catalogToRemove.Item2); + } + + this._loadedFiles = afterFiles.ToReadOnlyCollection(); + + // Lastly complete any changes added to the atomicComposition during the change event + atomicComposition.Complete(); + + // Break out of the while(true) + break; + } // WriteLock + } // AtomicComposition + } // while (true) + + var changedArgs = new ComposablePartCatalogChangeEventArgs(addedDefinitions, removedDefinitions, null); + this.OnChanged(changedArgs); + } + + /// <summary> + /// Returns a string representation of the directory catalog. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the string representation of the <see cref="DirectoryCatalog"/>. + /// </returns> + public override string ToString() + { + return GetDisplayName(); + } + + private AssemblyCatalog CreateAssemblyCatalogGuarded(string assemblyFilePath) + { + Exception exception = null; + + try + { +#if FEATURE_REFLECTIONCONTEXT + return (this._reflectionContext != null) + ? new AssemblyCatalog(assemblyFilePath, this._reflectionContext, this) + : new AssemblyCatalog(assemblyFilePath, this); +#else + return new AssemblyCatalog(assemblyFilePath, this); +#endif //FEATURE_REFLECTIONCONTEXT + } + catch (FileNotFoundException ex) + { // Files should always exists but don't blow up here if they don't + exception = ex; + } + catch (FileLoadException ex) + { // File was found but could not be loaded + exception = ex; + } + catch (BadImageFormatException ex) + { // Dlls that contain native code are not loaded, but do not invalidate the Directory + exception = ex; + } + catch (ReflectionTypeLoadException ex) + { // Dlls that have missing Managed dependencies are not loaded, but do not invalidate the Directory + exception = ex; + } + + CompositionTrace.AssemblyLoadFailed(this, assemblyFilePath, exception); + + return null; + } + + private void DiffChanges(string[] beforeFiles, string[] afterFiles, + out List<Tuple<string, AssemblyCatalog>> catalogsToAdd, + out List<Tuple<string, AssemblyCatalog>> catalogsToRemove) + { + catalogsToAdd = new List<Tuple<string, AssemblyCatalog>>(); + catalogsToRemove = new List<Tuple<string, AssemblyCatalog>>(); + + IEnumerable<string> filesToAdd = afterFiles.Except(beforeFiles); + foreach (string file in filesToAdd) + { + AssemblyCatalog catalog = CreateAssemblyCatalogGuarded(file); + + if (catalog != null) + { + catalogsToAdd.Add(new Tuple<string, AssemblyCatalog>(file, catalog)); + } + } + + IEnumerable<string> filesToRemove = beforeFiles.Except(afterFiles); + using (new ReadLock(this._thisLock)) + { + foreach (string file in filesToRemove) + { + AssemblyCatalog catalog; + if (this._assemblyCatalogs.TryGetValue(file, out catalog)) + { + catalogsToRemove.Add(new Tuple<string, AssemblyCatalog>(file, catalog)); + } + } + } + } + + private string GetDisplayName() + { + return string.Format(CultureInfo.CurrentCulture, + "{0} (Path=\"{1}\")", // NOLOC + this.GetType().Name, + this._path); + } + + private string[] GetFiles() + { + string[] files = Directory.GetFiles(this._fullPath, this._searchPattern); + return Array.ConvertAll<string, string>(files, (file) => file.ToUpperInvariant()); + } + + private static string GetFullPath(string path) + { + if (!IOPath.IsPathRooted(path) && AppDomain.CurrentDomain.BaseDirectory != null) + { + path = IOPath.Combine(AppDomain.CurrentDomain.BaseDirectory, path); + } + + return IOPath.GetFullPath(path).ToUpperInvariant(); + } + + private void Initialize(string path, string searchPattern) + { + this._path = path; + this._fullPath = GetFullPath(path); + this._searchPattern = searchPattern; + this._assemblyCatalogs = new Dictionary<string, AssemblyCatalog>(); + this._catalogCollection = new ComposablePartCatalogCollection(null, null, null); + + this._loadedFiles = GetFiles().ToReadOnlyCollection(); + + foreach (string file in this._loadedFiles) + { + AssemblyCatalog assemblyCatalog = null; + assemblyCatalog = CreateAssemblyCatalogGuarded(file); + + if (assemblyCatalog != null) + { + this._assemblyCatalogs.Add(file, assemblyCatalog); + this._catalogCollection.Add(assemblyCatalog); + } + } + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + /// <summary> + /// Gets the display name of the directory catalog. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a human-readable display name of the <see cref="DirectoryCatalog"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + /// <summary> + /// Gets the composition element from which the directory catalog originated. + /// </summary> + /// <value> + /// This property always returns <see langword="null"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + ICompositionElement ICompositionElement.Origin + { + get { return null; } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.GetExportOverrides.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.GetExportOverrides.cs new file mode 100644 index 00000000000..3915089fd34 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.GetExportOverrides.cs @@ -0,0 +1,819 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Collections.ObjectModel; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.ComponentModel.Composition.ReflectionModel; + +namespace System.ComponentModel.Composition.Hosting +{ + public abstract partial class ExportProvider + { + /// <summary> + /// Returns the export with the contract name derived from the specified type parameter, + /// throwing an exception if there is not exactly one matching export. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T}"/> object to return. The contract name is also + /// derived from this type parameter. + /// </typeparam> + /// <returns> + /// The <see cref="Lazy{T}"/> object with the contract name derived from + /// <typeparamref name="T"/>. + /// </returns> + /// <remarks> + /// <para> + /// The returned <see cref="Lazy{T}"/> object is an instance of + /// <see cref="Lazy{T, TMetadataView}"/> underneath, where + /// <c>TMetadataView</c> + /// is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c> + /// is <see cref="String"/> and <c>TValue</c> is <see cref="Object"/>. + /// </para> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are zero <see cref="Lazy{T}"/> objects with the contract name derived + /// from <typeparamref name="T"/> in the <see cref="CompositionContainer"/>. + /// </para> + /// -or- + /// <para> + /// There are more than one <see cref="Lazy{T}"/> objects with the contract name + /// derived from <typeparamref name="T"/> in the <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public Lazy<T> GetExport<T>() + { + return this.GetExport<T>((string)null); + } + + /// <summary> + /// Returns the export with the specified contract name, throwing an exception if there + /// is not exactly one matching export. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T}"/> object to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the <see cref="Lazy{T}"/> + /// object to return; or <see langword="null"/> or an empty string ("") to use the + /// default contract name. + /// </param> + /// <returns> + /// The <see cref="Lazy{T}"/> object with the specified contract name. + /// </returns> + /// <remarks> + /// <para> + /// The returned <see cref="Lazy{T}"/> object is an instance of + /// <see cref="Lazy{T, TMetadataView}"/> underneath, where + /// <c>TMetadataView</c> + /// is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c> + /// is <see cref="String"/> and <c>TValue</c> is <see cref="Object"/>. + /// </para> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The default contract name is compared using a case-sensitive, non-linguistic + /// comparison using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are zero <see cref="Lazy{T}"/> objects with the specified contract name + /// in the <see cref="CompositionContainer"/>. + /// </para> + /// -or- + /// <para> + /// There are more than one <see cref="Lazy{T}"/> objects with the specified contract + /// name in the <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public Lazy<T> GetExport<T>(string contractName) + { + return this.GetExportCore<T>(contractName); + } + + /// <summary> + /// Returns the export with the contract name derived from the specified type parameter, + /// throwing an exception if there is not exactly one matching export. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T, TMetadataView}"/> object to return. The + /// contract name is also derived from this type parameter. + /// </typeparam> + /// <typeparam name="TMetadataView"> + /// The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> object + /// to return. + /// </typeparam> + /// <returns> + /// The <see cref="Lazy{T, TMetadataView}"/> object with the contract name derived + /// from <typeparamref name="T"/>. + /// </returns> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are zero <see cref="Lazy{T, TMetadataView}"/> objects with the contract + /// name derived from <typeparamref name="T"/> in the + /// <see cref="CompositionContainer"/>. + /// </para> + /// -or- + /// <para> + /// There are more than one <see cref="Lazy{T, TMetadataView}"/> objects with the + /// contract name derived from <typeparamref name="T"/> in the + /// <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="InvalidOperationException"> + /// <typeparamref name="TMetadataView"/> is not a valid metadata view type. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public Lazy<T, TMetadataView> GetExport<T, TMetadataView>() + { + return this.GetExport<T, TMetadataView>((string)null); + } + + /// <summary> + /// Returns the export with the specified contract name, throwing an exception if there + /// is not exactly one matching export. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T, TMetadataView}"/> object to return. + /// </typeparam> + /// <typeparam name="TMetadataView"> + /// The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> object + /// to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Lazy{T, TMetadataView}"/> object to return; or <see langword="null"/> + /// or an empty string ("") to use the default contract name. + /// </param> + /// <returns> + /// The <see cref="Lazy{T, TMetadataView}"/> object with the specified contract name. + /// </returns> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are zero <see cref="Lazy{T, TMetadataView}"/> objects with the + /// specified contract name in the <see cref="CompositionContainer"/>. + /// </para> + /// -or- + /// <para> + /// There are more than one <see cref="Lazy{T, TMetadataView}"/> objects with the + /// specified contract name in the <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="InvalidOperationException"> + /// <typeparamref name="TMetadataView"/> is not a valid metadata view type. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + public Lazy<T, TMetadataView> GetExport<T, TMetadataView>(string contractName) + { + return this.GetExportCore<T, TMetadataView>(contractName); + } + + /// <summary> + /// Returns the exports with the specified contract name. + /// </summary> + /// <param name="type"> + /// The <see cref="Type"/> of the <see cref="Export"/> objects to return. + /// </param> + /// <param name="metadataViewType"> + /// The <see cref="Type"/> of the metadata view of the <see cref="Export"/> objects to + /// return. + /// </param> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Export"/> object to return; or <see langword="null"/> + /// or an empty string ("") to use the default contract name. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> containing the <see cref="Lazy{Object, Object}"/> objects + /// with the specified contract name, if found; otherwise, an empty + /// <see cref="IEnumerable{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The returned <see cref="Export"/> objects are instances of + /// <see cref="Lazy{T, TMetadataView}"/> underneath, where <c>T</c> + /// is <paramref name="type"/> and <c>TMetadataView</c> is + /// <paramref name="metadataViewType"/>. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <paramref name="type"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ArgumentNullException"> + /// <paramref name="type"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="InvalidOperationException"> + /// <paramref name="metadataViewType"/> is not a valid metadata view type. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006")] + public IEnumerable<Lazy<object, object>> GetExports(Type type, Type metadataViewType, string contractName) + { + IEnumerable<Export> exports = this.GetExportsCore(type, metadataViewType, contractName, ImportCardinality.ZeroOrMore); + Collection<Lazy<object, object>> result = new Collection<Lazy<object, object>>(); + + Func<Export, Lazy<object, object>> typedExportFactory = ExportServices.CreateSemiStronglyTypedLazyFactory(type, metadataViewType); + foreach (Export export in exports) + { + result.Add(typedExportFactory.Invoke(export)); + } + + return result; + } + + /// <summary> + /// Returns the exports with the contract name derived from the specified type parameter. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T}"/> objects to return. The contract name is also + /// derived from this type parameter. + /// </typeparam> + /// <returns> + /// An <see cref="IEnumerable{T}"/> containing the <see cref="Lazy{T}"/> objects + /// with the contract name derived from <typeparamref name="T"/>, if found; otherwise, + /// an empty <see cref="IEnumerable{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The returned <see cref="Lazy{T}"/> objects are instances of + /// <see cref="Lazy{T, TMetadataView}"/> underneath, where + /// <c>TMetadataView</c> + /// is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c> + /// is <see cref="String"/> and <c>TValue</c> is <see cref="Object"/>. + /// </para> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006")] + public IEnumerable<Lazy<T>> GetExports<T>() + { + return this.GetExports<T>((string)null); + } + + /// <summary> + /// Returns the exports with the specified contract name. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T}"/> objects to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the <see cref="Lazy{T}"/> + /// objects to return; or <see langword="null"/> or an empty string ("") to use the + /// default contract name. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> containing the <see cref="Lazy{T}"/> objects + /// with the specified contract name, if found; otherwise, an empty + /// <see cref="IEnumerable{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The returned <see cref="Lazy{T}"/> objects are instances of + /// <see cref="Lazy{T, TMetadataView}"/> underneath, where + /// <c>TMetadataView</c> + /// is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c> + /// is <see cref="String"/> and <c>TValue</c> is <see cref="Object"/>. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006")] + public IEnumerable<Lazy<T>> GetExports<T>(string contractName) + { + return this.GetExportsCore<T>(contractName); + } + + /// <summary> + /// Returns the exports with the contract name derived from the specified type parameter. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T, TMetadataView}"/> objects to return. The + /// contract name is also derived from this type parameter. + /// </typeparam> + /// <typeparam name="TMetadataView"> + /// The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> objects + /// to return. + /// </typeparam> + /// <returns> + /// An <see cref="IEnumerable{T}"/> containing the + /// <see cref="Lazy{T, TMetadataView}"/> objects with the contract name derived from + /// <typeparamref name="T"/>, if found; otherwise, an empty + /// <see cref="IEnumerable{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="InvalidOperationException"> + /// <typeparamref name="TMetadataView"/> is not a valid metadata view type. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006")] + public IEnumerable<Lazy<T, TMetadataView>> GetExports<T, TMetadataView>() + { + return this.GetExports<T, TMetadataView>((string)null); + } + + /// <summary> + /// Returns the exports with the specified contract name. + /// </summary> + /// <typeparam name="T"> + /// The type of the <see cref="Lazy{T, TMetadataView}"/> objects to return. The + /// contract name is also derived from this type parameter. + /// </typeparam> + /// <typeparam name="TMetadataView"> + /// The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> objects + /// to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Lazy{T, TMetadataView}"/> objects to return; or <see langword="null"/> + /// or an empty string ("") to use the default contract name. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> containing the + /// <see cref="Lazy{T, TMetadataView}"/> objects with the specified contract name if + /// found; otherwise, an empty <see cref="IEnumerable{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="InvalidOperationException"> + /// <typeparamref name="TMetadataView"/> is not a valid metadata view type. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006")] + public IEnumerable<Lazy<T, TMetadataView>> GetExports<T, TMetadataView>(string contractName) + { + return this.GetExportsCore<T, TMetadataView>(contractName); + } + + /// <summary> + /// Returns the exported value with the contract name derived from the specified type + /// parameter, throwing an exception if there is not exactly one matching exported value. + /// </summary> + /// <typeparam name="T"> + /// The type of the exported value to return. The contract name is also + /// derived from this type parameter. + /// </typeparam> + /// <returns> + /// The exported <see cref="Object"/> with the contract name derived from + /// <typeparamref name="T"/>. + /// </returns> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="CompositionContractMismatchException"> + /// The underlying exported value cannot be cast to <typeparamref name="T"/>. + /// </exception> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are zero exported values with the contract name derived from + /// <typeparamref name="T"/> in the <see cref="CompositionContainer"/>. + /// </para> + /// -or- + /// <para> + /// There are more than one exported values with the contract name derived from + /// <typeparamref name="T"/> in the <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + public T GetExportedValue<T>() + { + return this.GetExportedValue<T>((string)null); + } + + /// <summary> + /// Returns the exported value with the specified contract name, throwing an exception + /// if there is not exactly one matching exported value. + /// </summary> + /// <typeparam name="T"> + /// The type of the exported value to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the exported value to return, + /// or <see langword="null"/> or an empty string ("") to use the default contract name. + /// </param> + /// <returns> + /// The exported <see cref="Object"/> with the specified contract name. + /// </returns> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="CompositionContractMismatchException"> + /// The underlying exported value cannot be cast to <typeparamref name="T"/>. + /// </exception> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are zero exported values with the specified contract name in the + /// <see cref="CompositionContainer"/>. + /// </para> + /// -or- + /// <para> + /// There are more than one exported values with the specified contract name in the + /// <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + public T GetExportedValue<T>(string contractName) + { + return this.GetExportedValueCore<T>(contractName, ImportCardinality.ExactlyOne); + } + + /// <summary> + /// Returns the exported value with the contract name derived from the specified type + /// parameter, throwing an exception if there is more than one matching exported value. + /// </summary> + /// <typeparam name="T"> + /// The type of the exported value to return. The contract name is also + /// derived from this type parameter. + /// </typeparam> + /// <returns> + /// The exported <see cref="Object"/> with the contract name derived from + /// <typeparamref name="T"/>, if found; otherwise, the default value for + /// <typeparamref name="T"/>. + /// </returns> + /// <remarks> + /// <para> + /// If the exported value is not found, then this method returns the appropriate + /// default value for <typeparamref name="T"/>; for example, 0 (zero) for integer + /// types, <see langword="false"/> for Boolean types, and <see langword="null"/> + /// for reference types. + /// </para> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="CompositionContractMismatchException"> + /// The underlying exported value cannot be cast to <typeparamref name="T"/>. + /// </exception> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// There are more than one exported values with the contract name derived from + /// <typeparamref name="T"/> in the <see cref="CompositionContainer"/>. + /// </para> + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + public T GetExportedValueOrDefault<T>() + { + return this.GetExportedValueOrDefault<T>((string)null); + } + + /// <summary> + /// Returns the exported value with the specified contract name, throwing an exception + /// if there is more than one matching exported value. + /// </summary> + /// <typeparam name="T"> + /// The type of the exported value to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the exported value to return, + /// or <see langword="null"/> or an empty string ("") to use the default contract name. + /// </param> + /// <returns> + /// The exported <see cref="Object"/> with the specified contract name, if found; + /// otherwise, the default value for <typeparamref name="T"/>. + /// </returns> + /// <remarks> + /// <para> + /// If the exported value is not found, then this method returns the appropriate + /// default value for <typeparamref name="T"/>; for example, 0 (zero) for integer + /// types, <see langword="false"/> for Boolean types, and <see langword="null"/> + /// for reference types. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="CompositionContractMismatchException"> + /// The underlying exported value cannot be cast to <typeparamref name="T"/>. + /// </exception> + /// <exception cref="ImportCardinalityMismatchException"> + /// There are more than one exported values with the specified contract name in the + /// <see cref="CompositionContainer"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + public T GetExportedValueOrDefault<T>(string contractName) + { + return this.GetExportedValueCore<T>(contractName, ImportCardinality.ZeroOrOne); + } + + /// <summary> + /// Returns the exported values with the contract name derived from the specified type + /// parameter. + /// </summary> + /// <typeparam name="T"> + /// The type of the exported value to return. The contract name is also + /// derived from this type parameter. + /// </typeparam> + /// <returns> + /// An <see cref="Collection{T}"/> containing the exported values with the contract name + /// derived from the specified type parameter, if found; otherwise, an empty + /// <see cref="Collection{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="CompositionContractMismatchException"> + /// One or more of the underlying exported values cannot be cast to + /// <typeparamref name="T"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + public IEnumerable<T> GetExportedValues<T>() + { + return this.GetExportedValues<T>((string)null); + } + + /// <summary> + /// Returns the exported values with the specified contract name. + /// </summary> + /// <typeparam name="T"> + /// The type of the exported value to return. + /// </typeparam> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the exported values to + /// return; or <see langword="null"/> or an empty string ("") to use the default + /// contract name. + /// </param> + /// <returns> + /// An <see cref="Collection{T}"/> containing the exported values with the specified + /// contract name, if found; otherwise, an empty <see cref="Collection{T}"/>. + /// </returns> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + /// <exception cref="CompositionContractMismatchException"> + /// One or more of the underlying exported values cannot be cast to + /// <typeparamref name="T"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="CompositionContainer"/> has been disposed of. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + public IEnumerable<T> GetExportedValues<T>(string contractName) + { + return this.GetExportedValuesCore<T>(contractName); + } + + private IEnumerable<T> GetExportedValuesCore<T>(string contractName) + { + IEnumerable<Export> exports = this.GetExportsCore(typeof(T), (Type)null, contractName, ImportCardinality.ZeroOrMore); + + Collection<T> result = new Collection<T>(); + foreach (Export export in exports) + { + result.Add(ExportServices.GetCastedExportedValue<T>(export)); + } + return result; + } + + private T GetExportedValueCore<T>(string contractName, ImportCardinality cardinality) + { + Assumes.IsTrue(cardinality.IsAtMostOne()); + + Export export = this.GetExportsCore(typeof(T), (Type)null, contractName, cardinality).SingleOrDefault(); + + return (export != null) ? ExportServices.GetCastedExportedValue<T>(export) : default(T); + } + + private IEnumerable<Lazy<T>> GetExportsCore<T>(string contractName) + { + IEnumerable<Export> exports = this.GetExportsCore(typeof(T), (Type)null, contractName, ImportCardinality.ZeroOrMore); + + Collection<Lazy<T>> result = new Collection<Lazy<T>>(); + foreach (Export export in exports) + { + result.Add(ExportServices.CreateStronglyTypedLazyOfT<T>(export)); + } + return result; + } + + private IEnumerable<Lazy<T, TMetadataView>> GetExportsCore<T, TMetadataView>(string contractName) + { + IEnumerable<Export> exports = this.GetExportsCore(typeof(T), typeof(TMetadataView), contractName, ImportCardinality.ZeroOrMore); + + Collection<Lazy<T, TMetadataView>> result = new Collection<Lazy<T, TMetadataView>>(); + foreach (Export export in exports) + { + result.Add(ExportServices.CreateStronglyTypedLazyOfTM<T, TMetadataView>(export)); + } + return result; + } + + private Lazy<T, TMetadataView> GetExportCore<T, TMetadataView>(string contractName) + { + Export export = this.GetExportsCore(typeof(T), typeof(TMetadataView), contractName, ImportCardinality.ExactlyOne).SingleOrDefault(); + + return (export != null) ? ExportServices.CreateStronglyTypedLazyOfTM<T, TMetadataView>(export) : null; + } + + private Lazy<T> GetExportCore<T>(string contractName) + { + Export export = this.GetExportsCore(typeof(T), null, contractName, ImportCardinality.ExactlyOne).SingleOrDefault(); + + return (export != null) ? ExportServices.CreateStronglyTypedLazyOfT<T>(export) : null; + } + + private IEnumerable<Export> GetExportsCore(Type type, Type metadataViewType, string contractName, ImportCardinality cardinality) + { + // Only 'type' cannot be null - the other parameters have sensible defaults. + Requires.NotNull(type, "type"); + + if (string.IsNullOrEmpty(contractName)) + { + contractName = AttributedModelServices.GetContractName(type); + } + + if (metadataViewType == null) + { + metadataViewType = ExportServices.DefaultMetadataViewType; + } + + if (!MetadataViewProvider.IsViewTypeValid(metadataViewType)) + { + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidMetadataView, metadataViewType.Name)); + } + + ImportDefinition importDefinition = BuildImportDefinition(type, metadataViewType, contractName, cardinality); + return this.GetExports(importDefinition, null); + } + + private static ImportDefinition BuildImportDefinition(Type type, Type metadataViewType, string contractName, ImportCardinality cardinality) + { + Assumes.NotNull(type, metadataViewType, contractName); + + IEnumerable<KeyValuePair<string, Type>> requiredMetadata = CompositionServices.GetRequiredMetadata(metadataViewType); + IDictionary<string, object> metadata = CompositionServices.GetImportMetadata(type, null); + + string requiredTypeIdentity = null; + if (type != typeof(object)) + { + requiredTypeIdentity = AttributedModelServices.GetTypeIdentity(type); + } + + return new ContractBasedImportDefinition(contractName, requiredTypeIdentity, requiredMetadata, cardinality, false, true, CreationPolicy.Any, metadata); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.cs new file mode 100644 index 00000000000..a2c8bbb3766 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportProvider.cs @@ -0,0 +1,235 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// Defines the <see langword="abstract"/> base class for export providers, which provide + /// methods for retrieving <see cref="Export"/> objects. + /// </summary> + public abstract partial class ExportProvider + { + private static readonly Export[] EmptyExports = new Export[] { }; + + /// <summary> + /// Initializes a new instance of the <see cref="ExportProvider"/> class. + /// </summary> + protected ExportProvider() + { + } + + /// <summary> + /// Occurs when the exports in the <see cref="ExportProvider"/> have changed. + /// </summary> + public event EventHandler<ExportsChangeEventArgs> ExportsChanged; + + /// <summary> + /// Occurs when the exports in the <see cref="ExportProvider"/> are changing. + /// </summary> + public event EventHandler<ExportsChangeEventArgs> ExportsChanging; + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> objects to get. + /// </param> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and + /// there are zero <see cref="Export"/> objects that match the conditions of the specified + /// <see cref="ImportDefinition"/>. + /// </para> + /// -or- + /// <para> + /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or + /// <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/> + /// objects that match the conditions of the specified <see cref="ImportDefinition"/>. + /// </para> + /// </exception> + public IEnumerable<Export> GetExports(ImportDefinition definition) + { + return GetExports(definition, null); + } + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> objects to get. + /// </param> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ImportCardinalityMismatchException"> + /// <para> + /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> and + /// there are zero <see cref="Export"/> objects that match the conditions of the specified + /// <see cref="ImportDefinition"/>. + /// </para> + /// -or- + /// <para> + /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or + /// <see cref="ImportCardinality.ExactlyOne"/> and there are more than one <see cref="Export"/> + /// objects that match the conditions of the specified <see cref="ImportDefinition"/>. + /// </para> + /// </exception> + public IEnumerable<Export> GetExports(ImportDefinition definition, AtomicComposition atomicComposition) + { + Requires.NotNull(definition, "definition"); + Contract.Ensures(Contract.Result<IEnumerable<Export>>() != null); + + IEnumerable<Export> exports; + ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports); + switch(result) + { + case ExportCardinalityCheckResult.Match: + return exports; + case ExportCardinalityCheckResult.NoExports: + throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_NoExports, definition.ToString())); + default: + Assumes.IsTrue(result == ExportCardinalityCheckResult.TooManyExports); + throw new ImportCardinalityMismatchException(string.Format(CultureInfo.CurrentCulture, Strings.CardinalityMismatch_TooManyExports, definition.ToString())); + } + } + + /// <summary> + /// Returns all exports that match the conditions of the specified import. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> objects to get. + /// </param> + /// <param name="exports"> + /// When this method returns, contains an <see cref="IEnumerable{T}"/> of <see cref="Export"/> + /// objects that match the conditions defined by <see cref="ImportDefinition"/>, if found; + /// otherwise, an empty <see cref="IEnumerable{T}"/>. + /// </param> + /// <returns> + /// <see langword="true"/> if <see cref="ImportDefinition.Cardinality"/> is + /// <see cref="ImportCardinality.ZeroOrOne"/> or <see cref="ImportCardinality.ZeroOrMore"/> and + /// there are zero <see cref="Export"/> objects that match the conditions of the specified + /// <see cref="ImportDefinition"/>. <see langword="true"/> if + /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or + /// <see cref="ImportCardinality.ExactlyOne"/> and there is exactly one <see cref="Export"/> + /// that matches the conditions of the specified <see cref="ImportDefinition"/>; otherwise, + /// <see langword="false"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + public bool TryGetExports(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports) + { + Requires.NotNull(definition, "definition"); + + exports = null; + ExportCardinalityCheckResult result = this.TryGetExportsCore(definition, atomicComposition, out exports); + return (result == ExportCardinalityCheckResult.Match); + } + + /// <summary> + /// Returns all exports that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="Export"/> objects to return. + /// </param> + /// <result> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match + /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an + /// empty <see cref="IEnumerable{T}"/>. + /// </result> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this method should not treat cardinality-related mismatches + /// as errors, and should not throw exceptions in those cases. For instance, + /// if <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ExactlyOne"/> + /// and there are zero <see cref="Export"/> objects that match the conditions of the + /// specified <see cref="ImportDefinition"/>, an <see cref="IEnumerable{T}"/> should be returned. + /// </note> + /// </remarks> + protected abstract IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition); + + /// <summary> + /// Raises the <see cref="ExportsChanged"/> event. + /// </summary> + /// <param name="e"> + /// An <see cref="ExportsChangeEventArgs"/> containing the data for the event. + /// </param> + protected virtual void OnExportsChanged(ExportsChangeEventArgs e) + { + EventHandler<ExportsChangeEventArgs> changedEvent = this.ExportsChanged; + if (changedEvent != null) + { + CompositionResult result = CompositionServices.TryFire(changedEvent, this, e); + result.ThrowOnErrors(e.AtomicComposition); + } + } + + /// <summary> + /// Raises the <see cref="ExportsChanging"/> event. + /// </summary> + /// <param name="e"> + /// An <see cref="ExportsChangeEventArgs"/> containing the data for the event. + /// </param> + protected virtual void OnExportsChanging(ExportsChangeEventArgs e) + { + EventHandler<ExportsChangeEventArgs> changingEvent = this.ExportsChanging; + if (changingEvent != null) + { + CompositionResult result = CompositionServices.TryFire(changingEvent, this, e); + result.ThrowOnErrors(e.AtomicComposition); + } + } + + private ExportCardinalityCheckResult TryGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable<Export> exports) + { + Assumes.NotNull(definition); + + exports = this.GetExportsCore(definition, atomicComposition); + + var checkResult = ExportServices.CheckCardinality(definition, exports); + + // Export providers treat >1 match as zero for cardinality 0-1 imports + // If this policy is moved we need to revisit the assumption that the + // ImportEngine made during previewing the only required imports to + // now also preview optional imports. + if (checkResult == ExportCardinalityCheckResult.TooManyExports && + definition.Cardinality == ImportCardinality.ZeroOrOne) + { + checkResult = ExportCardinalityCheckResult.Match; + exports = null; + } + + if (exports == null) + { + exports = EmptyExports; + } + + return checkResult; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportsChangeEventArgs.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportsChangeEventArgs.cs new file mode 100644 index 00000000000..f53eb9e029f --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ExportsChangeEventArgs.cs @@ -0,0 +1,128 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.Contracts; +using System.Linq; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// Provides data for the <see cref="ExportProvider.ExportsChanged"/> and + /// <see cref="ExportProvider.ExportsChanging"/> events. + /// </summary> + public class ExportsChangeEventArgs : EventArgs + { + private readonly IEnumerable<ExportDefinition> _addedExports; + private readonly IEnumerable<ExportDefinition> _removedExports; + private IEnumerable<string> _changedContractNames = null; + + /// <summary> + /// Initializes a new instance of the <see cref="ExportsChangeEventArgs"/> class with + /// the specified changed export definitions. + /// </summary> + /// <param name="addedExports"> + /// An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/>s of the exports + /// that have been added. + /// </param> + /// <param name="removedExports"> + /// An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/>s of the exports + /// that have been removed. + /// </param> + /// <param name="atomicComposition"> + /// A <see cref="AtomicComposition"/> representing all tentative changes that will + /// be completed if the change is successful, or discarded if it is not. + /// <see langword="null"/> if being applied outside a <see cref="AtomicComposition"/> + /// or during a <see cref="ExportProvider.ExportsChanged"/> event. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="addedExports"/> or <paramref name="removedExports"/> is <see langword="null"/>. + /// </exception> + public ExportsChangeEventArgs(IEnumerable<ExportDefinition> addedExports, + IEnumerable<ExportDefinition> removedExports, AtomicComposition atomicComposition) + { + Requires.NotNull(addedExports, "addedExports"); + Requires.NotNull(removedExports, "removedExports"); + + this._addedExports = addedExports.AsArray(); + this._removedExports = removedExports.AsArray(); + this.AtomicComposition = atomicComposition; + } + + /// <summary> + /// Gets the export definitions for the exports that have been added. + /// </summary> + /// <value> + /// A <see cref="IEnumerable{T}"/> of ExportDefinitions representing + /// the exports that have been added to the <see cref="CompositionContainer"/>. + /// </value> + public IEnumerable<ExportDefinition> AddedExports + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ExportDefinition>>() != null); + + return this._addedExports; + } + } + + /// <summary> + /// Gets the export definitions for the exports that have been removed. + /// </summary> + /// <value> + /// A <see cref="IEnumerable{T}"/> of ExportDefinitions representing + /// the exports that have been added to the <see cref="CompositionContainer"/>. + /// </value> + public IEnumerable<ExportDefinition> RemovedExports + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<ExportDefinition>>() != null); + + return this._removedExports; + } + } + + /// <summary> + /// Gets the contract names of the exports that have changed. + /// </summary> + /// <value> + /// A <see cref="IEnumerable{T}"/> of strings representing the contract names of + /// the exports that have changed in the <see cref="CompositionContainer"/>. + /// </value> + public IEnumerable<string> ChangedContractNames + { + get + { + if (this._changedContractNames == null) + { + this._changedContractNames = this.AddedExports + .Concat(this.RemovedExports) + .Select(export => export.ContractName) + .Distinct() + .ToArray(); + } + return this._changedContractNames; + } + } + + /// <summary> + /// Gets the atomicComposition, if any, that this change applies to. + /// </summary> + /// <value> + /// A <see cref="AtomicComposition"/> that this set of changes applies too. + /// + /// It can be <see langword="null"/> if the changes are being applied outside a + /// <see cref="AtomicComposition"/> or during a + /// <see cref="ExportProvider.ExportsChanged"/> event. + /// + /// When the value is non-null it should be used to record temporary changed state + /// and actions that will be executed when the atomicComposition is completeed. + /// </value> + public AtomicComposition AtomicComposition { get; private set; } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependenciesTraversal.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependenciesTraversal.cs new file mode 100644 index 00000000000..062bd1e34bf --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependenciesTraversal.cs @@ -0,0 +1,96 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class FilteredCatalog + { + internal class DependenciesTraversal : IComposablePartCatalogTraversal + { + private IEnumerable<ComposablePartDefinition> _parts; + private Func<ImportDefinition, bool> _importFilter; + private Dictionary<string, List<ComposablePartDefinition>> _exportersIndex; + + public DependenciesTraversal(FilteredCatalog catalog, Func<ImportDefinition, bool> importFilter) + { + Assumes.NotNull(catalog); + Assumes.NotNull(importFilter); + + this._parts = catalog._innerCatalog; + this._importFilter = importFilter; + } + + public void Initialize() + { + this.BuildExportersIndex(); + } + + private void BuildExportersIndex() + { + this._exportersIndex = new Dictionary<string, List<ComposablePartDefinition>>(); + foreach (ComposablePartDefinition part in this._parts) + { + foreach (var export in part.ExportDefinitions) + { + this.AddToExportersIndex(export.ContractName, part); + } + } + } + + private void AddToExportersIndex(string contractName, ComposablePartDefinition part) + { + List<ComposablePartDefinition> parts = null; + if (!this._exportersIndex.TryGetValue(contractName, out parts)) + { + parts = new List<ComposablePartDefinition>(); + this._exportersIndex.Add(contractName, parts); + } + parts.Add(part); + } + + public bool TryTraverse(ComposablePartDefinition part, out IEnumerable<ComposablePartDefinition> reachableParts) + { + reachableParts = null; + List<ComposablePartDefinition> reachablePartList = null; + + // Go through all part imports + foreach (ImportDefinition import in part.ImportDefinitions.Where(this._importFilter)) + { + // Find all parts that we know will import each export + List<ComposablePartDefinition> candidateReachableParts = null; + foreach (var contractName in import.GetCandidateContractNames(part)) + { + if (this._exportersIndex.TryGetValue(contractName, out candidateReachableParts)) + { + // find if they actually match + foreach (var candidateReachablePart in candidateReachableParts) + { + foreach (ExportDefinition export in candidateReachablePart.ExportDefinitions) + { + if (import.IsImportDependentOnPart(candidateReachablePart, export, part.IsGeneric() != candidateReachablePart.IsGeneric())) + { + if (reachablePartList == null) + { + reachablePartList = new List<ComposablePartDefinition>(); + } + reachablePartList.Add(candidateReachablePart); + } + } + } + } + } + } + + reachableParts = reachablePartList; + return (reachableParts != null); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependentsTraversal.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependentsTraversal.cs new file mode 100644 index 00000000000..e4593f18da4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.DependentsTraversal.cs @@ -0,0 +1,103 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class FilteredCatalog + { + /// <summary> + /// Implementation of IComposablePartTraversal supporting the Dependents traveral pattern. + /// The implementation is optimized for a situation when the traversal is expected to be rather short-lived - that is, + /// if the chains of dependecies are rather small. To achieve that we do a very minimal structure prep upfront - merely creating a contract-based + /// index of imports - and the verify the full match of imports during the traversal. Given that most parts have a very few imports this should perform well. + /// </summary> + internal class DependentsTraversal : IComposablePartCatalogTraversal + { + private IEnumerable<ComposablePartDefinition> _parts; + private Func<ImportDefinition, bool> _importFilter; + private Dictionary<string, List<ComposablePartDefinition>> _importersIndex; + + public DependentsTraversal(FilteredCatalog catalog, Func<ImportDefinition, bool> importFilter) + { + Assumes.NotNull(catalog); + Assumes.NotNull(importFilter); + + this._parts = catalog._innerCatalog; + this._importFilter = importFilter; + } + + public void Initialize() + { + this.BuildImportersIndex(); + } + + private void BuildImportersIndex() + { + this._importersIndex = new Dictionary<string, List<ComposablePartDefinition>>(); + foreach (ComposablePartDefinition part in this._parts) + { + foreach (var import in part.ImportDefinitions) + { + foreach (var contractName in import.GetCandidateContractNames(part)) + { + this.AddToImportersIndex(contractName, part); + } + } + } + } + + + private void AddToImportersIndex(string contractName, ComposablePartDefinition part) + { + List<ComposablePartDefinition> parts = null; + if (!this._importersIndex.TryGetValue(contractName, out parts)) + { + parts = new List<ComposablePartDefinition>(); + this._importersIndex.Add(contractName, parts); + } + parts.Add(part); + } + + public bool TryTraverse(ComposablePartDefinition part, out IEnumerable<ComposablePartDefinition> reachableParts) + { + reachableParts = null; + List<ComposablePartDefinition> reachablePartList = null; + + // Go through all part exports + foreach (ExportDefinition export in part.ExportDefinitions) + { + // Find all parts that we know will import each export + List<ComposablePartDefinition> candidateReachableParts = null; + if (this._importersIndex.TryGetValue(export.ContractName, out candidateReachableParts)) + { + // find if they actually match + foreach (var candidateReachablePart in candidateReachableParts) + { + foreach (ImportDefinition import in candidateReachablePart.ImportDefinitions.Where(this._importFilter)) + { + if (import.IsImportDependentOnPart(part, export, part.IsGeneric() != candidateReachablePart.IsGeneric())) + { + if (reachablePartList == null) + { + reachablePartList = new List<ComposablePartDefinition>(); + } + reachablePartList.Add(candidateReachablePart); + } + } + } + } + } + + reachableParts = reachablePartList; + return (reachableParts != null); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.IComposablePartCatalogTraversal.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.IComposablePartCatalogTraversal.cs new file mode 100644 index 00000000000..b2f3609c562 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.IComposablePartCatalogTraversal.cs @@ -0,0 +1,27 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class FilteredCatalog + { + /// <summary> + /// This is designed to traverse a set of parts based on whatever pattern. There are no real expectations + /// as to what the pattern is and what properties is posseses + /// NOTE : we both with this interface - as opposed to just a simple delegate - due to minute performance reasons, + /// as this will be invoked very often. Also, each traversal is typically associated with a big state bag, which is + /// easier to associte with an explicit implementation as opposed to an implicit closure. + /// </summary> + internal interface IComposablePartCatalogTraversal + { + void Initialize(); + bool TryTraverse(ComposablePartDefinition part, out IEnumerable<ComposablePartDefinition> reachableParts); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.Traversal.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.Traversal.cs new file mode 100644 index 00000000000..76a59ebb2a5 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.Traversal.cs @@ -0,0 +1,134 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class FilteredCatalog + { + /// <summary> + /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the orignal filtered catalog and all their dependecies. + /// </summary> + /// <returns></returns> + public FilteredCatalog IncludeDependencies() + { + return this.IncludeDependencies(i => i.Cardinality == ImportCardinality.ExactlyOne); + } + + /// <summary> + /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the orignal filtered catalog and all their dependencies that + /// can be reached via imports that match the specified filter. + /// </summary> + /// <param name="importFilter">The import filter.</param> + /// <returns></returns> + public FilteredCatalog IncludeDependencies(Func<ImportDefinition, bool> importFilter) + { + Requires.NotNull(importFilter, "importFilter"); + this.ThrowIfDisposed(); + + return Traverse(new DependenciesTraversal(this, importFilter)); + } + + /// <summary> + /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the orignal filtered catalog and all their dependents. + /// </summary> + /// <returns></returns> + public FilteredCatalog IncludeDependents() + { + return this.IncludeDependents(i => i.Cardinality == ImportCardinality.ExactlyOne); + } + + /// <summary> + /// Creates a new instance of the <see cref="FilteredCatalog"/> that conatains all the parts from the orignal filtered catalog and all their dependents that + /// can be reached via imports that match the specified filter. + /// </summary> + /// <param name="importFilter">The import filter.</param> + /// <returns></returns> + public FilteredCatalog IncludeDependents(Func<ImportDefinition, bool> importFilter) + { + Requires.NotNull(importFilter, "importFilter"); + this.ThrowIfDisposed(); + + return Traverse(new DependentsTraversal(this, importFilter)); + } + + private FilteredCatalog Traverse(IComposablePartCatalogTraversal traversal) + { + Assumes.NotNull(traversal); + + // we make sure that the underlyiong catalog cannot change while we are doing the trasversal + // After thaty traversal is done, the freeze is lifted, and the catalog is free to change, but the changes + // cannot affect partitioning + this.FreezeInnerCatalog(); + + try + { + traversal.Initialize(); + var traversalClosure = GetTraversalClosure(this._innerCatalog.Where(this._filter), traversal); + return new FilteredCatalog(this._innerCatalog, p => traversalClosure.Contains(p)); + } + finally + { + this.UnfreezeInnerCatalog(); + } + } + + private static HashSet<ComposablePartDefinition> GetTraversalClosure(IEnumerable<ComposablePartDefinition> parts, IComposablePartCatalogTraversal traversal) + { + Assumes.NotNull(traversal); + + var traversedParts = new HashSet<ComposablePartDefinition>(); + GetTraversalClosure(parts, traversedParts, traversal); + return traversedParts; + } + + private static void GetTraversalClosure(IEnumerable<ComposablePartDefinition> parts, HashSet<ComposablePartDefinition> traversedParts, IComposablePartCatalogTraversal traversal) + { + foreach (var part in parts) + { + if (traversedParts.Add(part)) + { + IEnumerable<ComposablePartDefinition> partsToTraverse = null; + if (traversal.TryTraverse(part, out partsToTraverse)) + { + GetTraversalClosure(partsToTraverse, traversedParts, traversal); + } + } + } + } + + + private void FreezeInnerCatalog() + { + INotifyComposablePartCatalogChanged innerNotifyCatalog = this._innerCatalog as INotifyComposablePartCatalogChanged; + if (innerNotifyCatalog != null) + { + innerNotifyCatalog.Changing += ThrowOnRecomposition; + } + } + + private void UnfreezeInnerCatalog() + { + INotifyComposablePartCatalogChanged innerNotifyCatalog = this._innerCatalog as INotifyComposablePartCatalogChanged; + if (innerNotifyCatalog != null) + { + innerNotifyCatalog.Changing -= ThrowOnRecomposition; + } + } + + private static void ThrowOnRecomposition(object sender, ComposablePartCatalogChangeEventArgs e) + { + throw new ChangeRejectedException(); // TODO - text + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.cs new file mode 100644 index 00000000000..eea7c7d296b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/FilteredCatalog.cs @@ -0,0 +1,260 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged + { + private Func<ComposablePartDefinition, bool> _filter; + private ComposablePartCatalog _innerCatalog; + private FilteredCatalog _complement; + private object _lock = new object(); + private volatile bool _isDisposed = false; + + /// <summary> + /// Initializes a new instance of the <see cref="FilteredCatalog"/> class. + /// </summary> + /// <param name="catalog">The catalog.</param> + /// <param name="filter">The filter.</param> + public FilteredCatalog(ComposablePartCatalog catalog, Func<ComposablePartDefinition, bool> filter) : + this(catalog, filter, null) + { + } + + internal FilteredCatalog(ComposablePartCatalog catalog, Func<ComposablePartDefinition, bool> filter, FilteredCatalog complement) + { + Requires.NotNull(catalog, "catalog"); + Requires.NotNull(filter, "filter"); + + this._innerCatalog = catalog; + this._filter = (p) => filter.Invoke(p.GetGenericPartDefinition() ?? p); + this._complement = complement; + + INotifyComposablePartCatalogChanged notifyCatalog = this._innerCatalog as INotifyComposablePartCatalogChanged; + if (notifyCatalog != null) + { + notifyCatalog.Changed += this.OnChangedInternal; + notifyCatalog.Changing += this.OnChangingInternal; + } + } + + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + if(!this._isDisposed) + { + INotifyComposablePartCatalogChanged notifyCatalog = null; + try + { + lock (this._lock) + { + if (!this._isDisposed) + { + this._isDisposed = true; + notifyCatalog = this._innerCatalog as INotifyComposablePartCatalogChanged; + this._innerCatalog = null; + } + } + } + finally + { + if (notifyCatalog != null) + { + notifyCatalog.Changed -= this.OnChangedInternal; + notifyCatalog.Changing -= this.OnChangingInternal; + } + } + } + } + } + finally + { + base.Dispose(disposing); + } + } + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + return this._innerCatalog.Where(this._filter).GetEnumerator(); + } + + /// <summary> + /// Gets the complement. + /// </summary> + /// <value>The complement.</value> + public FilteredCatalog Complement + { + get + { + this.ThrowIfDisposed(); + + if (this._complement == null) + { + FilteredCatalog complement = new FilteredCatalog(this._innerCatalog, p => !this._filter(p), this); + lock (this._lock) + { + if (this._complement == null) + { + Thread.MemoryBarrier(); + this._complement = complement; + complement = null; + } + } + + if (complement != null) + { + complement.Dispose(); + } + } + + return this._complement; + } + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return.</param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePartCatalog"/> has been disposed of. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>, if no + /// <see cref="ExportDefinition"/> match the conditions defined by + /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>. + /// </note> + /// </remarks> + public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + this.ThrowIfDisposed(); + Requires.NotNull(definition, "definition"); + + var exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); + foreach(var export in this._innerCatalog.GetExports(definition)) + { + if (this._filter(export.Item1)) + { + exports.Add(export); + } + } + + return exports; + } + + /// <summary> + /// Notify when the contents of the Catalog has changed. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed; + + + /// <summary> + /// Notify when the contents of the Catalog is changing. + /// </summary> + public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing; + + + /// <summary> + /// Raises the <see cref="E:Changed"/> event. + /// </summary> + /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param> + protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e) + { + EventHandler<ComposablePartCatalogChangeEventArgs> changedEvent = this.Changed; + if (changedEvent != null) + { + changedEvent.Invoke(this, e); + } + } + + /// <summary> + /// Raises the <see cref="E:Changing"/> event. + /// </summary> + /// <param name="e">The <see cref="System.ComponentModel.Composition.Hosting.ComposablePartCatalogChangeEventArgs"/> instance containing the event data.</param> + protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e) + { + EventHandler<ComposablePartCatalogChangeEventArgs> changingEvent = this.Changing; + if (changingEvent != null) + { + changingEvent.Invoke(this, e); + } + } + + private void OnChangedInternal(object sender, ComposablePartCatalogChangeEventArgs e) + { + var processedArgs = ProcessEventArgs(e); + if (processedArgs != null) + { + this.OnChanged(this.ProcessEventArgs(processedArgs)); + } + } + + private void OnChangingInternal(object sender, ComposablePartCatalogChangeEventArgs e) + { + var processedArgs = ProcessEventArgs(e); + if (processedArgs != null) + { + this.OnChanging(this.ProcessEventArgs(processedArgs)); + } + } + + private ComposablePartCatalogChangeEventArgs ProcessEventArgs(ComposablePartCatalogChangeEventArgs e) + { + // the constructor for ComposablePartCatalogChangeEventArgs takes a snapshot of the arguments, so we don't have to + var result = new ComposablePartCatalogChangeEventArgs( + e.AddedDefinitions.Where(this._filter), + e.RemovedDefinitions.Where(this._filter), + e.AtomicComposition); + + // Only fire if we need to + if (result.AddedDefinitions.FastAny() || result.RemovedDefinitions.FastAny()) + { + return result; + } + else + { + return null; + } + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/INotifyComposablePartCatalogChanged.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/INotifyComposablePartCatalogChanged.cs new file mode 100644 index 00000000000..28d013b1744 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/INotifyComposablePartCatalogChanged.cs @@ -0,0 +1,19 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// Notifications when a ComposablePartCatalog changes. + /// </summary> + public interface INotifyComposablePartCatalogChanged + { + event EventHandler<ComposablePartCatalogChangeEventArgs> Changed; + event EventHandler<ComposablePartCatalogChangeEventArgs> Changing; + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.EngineContext.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.EngineContext.cs new file mode 100644 index 00000000000..d5fb427d05b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.EngineContext.cs @@ -0,0 +1,84 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class ImportEngine + { + /// <summary> + /// Used to wrap the start and stop of enforcing export changes don't + /// break required imports. This context is stored in a AtomicComposition. + /// </summary> + private class EngineContext + { + private ImportEngine _importEngine; + private List<PartManager> _addedPartManagers = new List<PartManager>(); + private List<PartManager> _removedPartManagers = new List<PartManager>(); + private EngineContext _parentEngineContext; + + public EngineContext(ImportEngine importEngine, EngineContext parentEngineContext) + { + this._importEngine = importEngine; + this._parentEngineContext = parentEngineContext; + } + + public void AddPartManager(PartManager part) + { + Assumes.NotNull(part); + if (!this._removedPartManagers.Remove(part)) + { + this._addedPartManagers.Add(part); + } + } + + public void RemovePartManager(PartManager part) + { + Assumes.NotNull(part); + if (!this._addedPartManagers.Remove(part)) + { + this._removedPartManagers.Add(part); + } + } + + public IEnumerable<PartManager> GetAddedPartManagers() + { + if (this._parentEngineContext != null) + { + return this._addedPartManagers.ConcatAllowingNull(this._parentEngineContext.GetAddedPartManagers()); + } + return this._addedPartManagers; + } + + public IEnumerable<PartManager> GetRemovedPartManagers() + { + if (this._parentEngineContext != null) + { + return this._removedPartManagers.ConcatAllowingNull(this._parentEngineContext.GetRemovedPartManagers()); + } + return this._removedPartManagers; + } + + public void Complete() + { + foreach (var partManager in this._addedPartManagers) + { + this._importEngine.StartSatisfyingImports(partManager, null); + } + + foreach (var partManager in this._removedPartManagers) + { + this._importEngine.StopSatisfyingImports(partManager, null); + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.PartManager.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.PartManager.cs new file mode 100644 index 00000000000..2af4197c88e --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.PartManager.cs @@ -0,0 +1,211 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class ImportEngine + { + /// <summary> + /// Used by the <see cref="ImportEngine"/> to manage the composition of a given part. + /// It stores things like the list of disposable exports used to satisfy the imports as + /// well as the caching of the exports discovered during previewing of a part. + /// </summary> + private class PartManager + { + private Dictionary<ImportDefinition, List<IDisposable>> _importedDisposableExports; + private Dictionary<ImportDefinition, Export[]> _importCache; + private string[] _importedContractNames; + private ComposablePart _part; + private ImportState _state = ImportState.NoImportsSatisfied; + private readonly ImportEngine _importEngine; + + public PartManager(ImportEngine importEngine, ComposablePart part) + { + this._importEngine = importEngine; + this._part = part; + } + + public ComposablePart Part + { + get + { + return this._part; + } + } + + public ImportState State + { + get + { + using (this._importEngine._lock.LockStateForRead()) + { + return this._state; + } + } + set + { + using (this._importEngine._lock.LockStateForWrite()) + { + this._state = value; + } + } + } + + public bool TrackingImports { get; set; } + + public IEnumerable<string> GetImportedContractNames() + { + if (this.Part == null) + { + return Enumerable.Empty<string>(); + } + + if (this._importedContractNames == null) + { + this._importedContractNames = this.Part.ImportDefinitions.Select(import => import.ContractName ?? ImportDefinition.EmptyContractName).Distinct().ToArray(); + } + return this._importedContractNames; + } + + public CompositionResult TrySetImport(ImportDefinition import, IEnumerable<Export> exports) + { + try + { + this.Part.SetImport(import, exports); + UpdateDisposableDependencies(import, exports); + return CompositionResult.SucceededResult; + } + catch (CompositionException ex) + { // Pulling on one of the exports failed + + return new CompositionResult( + ErrorBuilder.CreatePartCannotSetImport(Part, import, ex)); + } + catch (ComposablePartException ex) + { // Type mismatch between export and import + + return new CompositionResult( + ErrorBuilder.CreatePartCannotSetImport(Part, import, ex)); + } + } + + public void SetSavedImport(ImportDefinition import, Export[] exports, AtomicComposition atomicComposition) + { + if (atomicComposition != null) + { + var savedExports = this.GetSavedImport(import); + + // Add a revert action to revert the stored exports + // in the case that this atomicComposition gets rolled back. + atomicComposition.AddRevertAction(() => + this.SetSavedImport(import, savedExports, null)); + } + + if (this._importCache == null) + { + this._importCache = new Dictionary<ImportDefinition, Export[]>(); + } + + this._importCache[import] = exports; + } + + public Export[] GetSavedImport(ImportDefinition import) + { + Export[] exports = null; + if (this._importCache != null) + { + // We don't care about the return value we just want the exports + // and if it isn't present we just return the initialized null value + this._importCache.TryGetValue(import, out exports); + } + return exports; + } + + public void ClearSavedImports() + { + this._importCache = null; + } + + public CompositionResult TryOnComposed() + { + try + { + this.Part.Activate(); + return CompositionResult.SucceededResult; + } + catch (ComposablePartException ex) + { // Type failed to be constructed, imports could not be set, etc + return new CompositionResult( + ErrorBuilder.CreatePartCannotActivate(this.Part, ex)); + } + } + + public void UpdateDisposableDependencies(ImportDefinition import, IEnumerable<Export> exports) + { + // Determine if there are any new disposable exports, optimizing for the most + // likely case, which is that there aren't any + List<IDisposable> disposableExports = null; + foreach (var disposableExport in exports.OfType<IDisposable>()) + { + if (disposableExports == null) + { + disposableExports = new List<IDisposable>(); + } + disposableExports.Add(disposableExport); + } + + // Dispose any existing references previously set on this import + List<IDisposable> oldDisposableExports = null; + if (this._importedDisposableExports != null && + this._importedDisposableExports.TryGetValue(import, out oldDisposableExports)) + { + oldDisposableExports.ForEach(disposable => disposable.Dispose()); + + // If there aren't any replacements, get rid of the old storage + if (disposableExports == null) + { + this._importedDisposableExports.Remove(import); + if (!this._importedDisposableExports.FastAny()) + { + this._importedDisposableExports = null; + } + + return; + } + } + + // Record the new collection + if (disposableExports != null) + { + if (this._importedDisposableExports == null) + { + this._importedDisposableExports = new Dictionary<ImportDefinition, List<IDisposable>>(); + } + this._importedDisposableExports[import] = disposableExports; + } + } + + public void DisposeAllDependencies() + { + if (this._importedDisposableExports != null) + { + IEnumerable<IDisposable> dependencies = this._importedDisposableExports.Values + .SelectMany(exports => exports); + + this._importedDisposableExports = null; + + dependencies.ForEach(disposableExport => disposableExport.Dispose()); + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.RecompositionManager.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.RecompositionManager.cs new file mode 100644 index 00000000000..ba1f98a77c9 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.RecompositionManager.cs @@ -0,0 +1,159 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + public partial class ImportEngine + { + /// <summary> + /// Used by the <see cref="ImportEngine"/> to effiecently store and retrieve the list of parts + /// that will be affected by changes to exports. This allows the <see cref="ImportEngine"/> to properly + /// block breaking changes and also recompose imports as appropriate. + /// </summary> + private class RecompositionManager + { + private WeakReferenceCollection<PartManager> _partsToIndex = new WeakReferenceCollection<PartManager>(); + private WeakReferenceCollection<PartManager> _partsToUnindex = new WeakReferenceCollection<PartManager>(); + private Dictionary<string, WeakReferenceCollection<PartManager>> _partManagerIndex = new Dictionary<string, WeakReferenceCollection<PartManager>>(); + + public void AddPartToIndex(PartManager partManager) + { + this._partsToIndex.Add(partManager); + } + + public void AddPartToUnindex(PartManager partManager) + { + this._partsToUnindex.Add(partManager); + } + + public IEnumerable<PartManager> GetAffectedParts(IEnumerable<string> changedContractNames) + { + this.UpdateImportIndex(); + + List<PartManager> parts = new List<PartManager>(); + + parts.AddRange(GetPartsImporting(ImportDefinition.EmptyContractName)); + + foreach (string contractName in changedContractNames) + { + parts.AddRange(GetPartsImporting(contractName)); + } + + return parts; + } + + public static IEnumerable<ImportDefinition> GetAffectedImports(ComposablePart part, IEnumerable<ExportDefinition> changedExports) + { + return part.ImportDefinitions.Where(import => IsAffectedImport(import, changedExports)); + } + + private static bool IsAffectedImport(ImportDefinition import, IEnumerable<ExportDefinition> changedExports) + { + // This could be more efficient still if the export definitions were indexed by contract name, + // only worth revisiting if we need to squeeze more performance out of recomposition + foreach (var export in changedExports) + { + if (import.IsConstraintSatisfiedBy(export)) + { + return true; + } + } + + return false; + } + + public IEnumerable<PartManager> GetPartsImporting(string contractName) + { + WeakReferenceCollection<PartManager> partManagerList; + if (!this._partManagerIndex.TryGetValue(contractName, out partManagerList)) + { + return Enumerable.Empty<PartManager>(); + } + + return partManagerList.AliveItemsToList(); + } + + private void AddIndexEntries(PartManager partManager) + { + foreach (string contractName in partManager.GetImportedContractNames()) + { + WeakReferenceCollection<PartManager> indexEntries; + if (!this._partManagerIndex.TryGetValue(contractName, out indexEntries)) + { + indexEntries = new WeakReferenceCollection<PartManager>(); + this._partManagerIndex.Add(contractName, indexEntries); + } + + if (!indexEntries.Contains(partManager)) + { + indexEntries.Add(partManager); + } + } + } + + private void RemoveIndexEntries(PartManager partManager) + { + foreach (string contractName in partManager.GetImportedContractNames()) + { + WeakReferenceCollection<PartManager> indexEntries; + if (this._partManagerIndex.TryGetValue(contractName, out indexEntries)) + { + indexEntries.Remove(partManager); + var aliveItems = indexEntries.AliveItemsToList(); + + if (aliveItems.Count == 0) + { + this._partManagerIndex.Remove(contractName); + } + } + } + } + + private void UpdateImportIndex() + { + var partsToIndex = this._partsToIndex.AliveItemsToList(); + this._partsToIndex.Clear(); + + var partsToUnindex = this._partsToUnindex.AliveItemsToList(); + this._partsToUnindex.Clear(); + + if (partsToIndex.Count == 0 && partsToUnindex.Count == 0) + { + return; + } + + foreach (var partManager in partsToIndex) + { + var index = partsToUnindex.IndexOf(partManager); + + // If the same part is being added and removed we can ignore both + if (index >= 0) + { + partsToUnindex[index] = null; + } + else + { + AddIndexEntries(partManager); + } + } + + foreach (var partManager in partsToUnindex) + { + if (partManager != null) + { + RemoveIndexEntries(partManager); + } + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.cs new file mode 100644 index 00000000000..7b0b04c0c1b --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportEngine.cs @@ -0,0 +1,771 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + // This class guarantees thread-safety under the following conditions: + // - Each composition is executed on a single thread + // - No recomposition ever takes place + // - The class is created with isThreadSafe=true + public partial class ImportEngine : ICompositionService, IDisposable + { + private const int MaximumNumberOfCompositionIterations = 100; + + private volatile bool _isDisposed; + private ExportProvider _sourceProvider; + private Stack<PartManager> _recursionStateStack = new Stack<PartManager>(); + private ConditionalWeakTable<ComposablePart, PartManager> _partManagers = new ConditionalWeakTable<ComposablePart, PartManager>(); + private RecompositionManager _recompositionManager = new RecompositionManager(); + private readonly CompositionLock _lock = null; + private readonly CompositionOptions _compositionOptions; + + /// <summary> + /// Initializes a new instance of the <see cref="ImportEngine"/> class. + /// </summary> + /// <param name="sourceProvider"> + /// The <see cref="ExportProvider"/> which provides the + /// <see cref="ImportEngine"/> access to <see cref="Export"/>s. + /// </param> + public ImportEngine(ExportProvider sourceProvider) + : this(sourceProvider, CompositionOptions.Default) + { + } + + public ImportEngine(ExportProvider sourceProvider, bool isThreadSafe) + : this(sourceProvider, isThreadSafe ? CompositionOptions.IsThreadSafe : CompositionOptions.Default) + { + } + + public ImportEngine(ExportProvider sourceProvider, CompositionOptions compositionOptions) + { + Requires.NotNull(sourceProvider, "sourceProvider"); + + this._compositionOptions = compositionOptions; + this._sourceProvider = sourceProvider; + this._sourceProvider.ExportsChanging += this.OnExportsChanging; + this._lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); + } + + /// <summary> + /// Previews all the required imports for the given <see cref="ComposablePart"/> to + /// ensure they can all be satisified. The preview does not actually set the imports + /// only ensures that they exist in the source provider. If the preview succeeds then + /// the <see cref="ImportEngine"/> also enforces that changes to exports in the source + /// provider will not break any of the required imports. If this enforcement needs to be + /// lifted for this part then <see cref="ReleaseImports"/> needs to be called for this + /// <see cref="ComposablePart"/>. + /// </summary> + /// <param name="part"> + /// The <see cref="ComposablePart"/> to preview the required imports. + /// </param> + /// <param name="atomicComposition"></param> + /// <exception cref="CompositionException"> + /// An error occurred during previewing and <paramref name="atomicComposition"/> is null. + /// <see cref="CompositionException.Errors"/> will contain a collection of errors that occurred. + /// The pre-existing composition is in an unknown state, depending on the errors that occured. + /// </exception> + /// <exception cref="ChangeRejectedException"> + /// An error occurred during the previewing and <paramref name="atomicComposition"/> is not null. + /// <see cref="CompositionException.Errors"/> will contain a collection of errors that occurred. + /// The pre-existing composition remains in valid state. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ImportEngine"/> has been disposed of. + /// </exception> + public void PreviewImports(ComposablePart part, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + + Requires.NotNull(part, "part"); + + // Do not do any previewing if SilentRejection is disabled. + if (this._compositionOptions.HasFlag(CompositionOptions.DisableSilentRejection)) + { + return; + } + + // NOTE : this is a very intricate area threading-wise, please use caution when changing, otherwise state corruption or deadlocks will ensue + // The gist of what we are doing is as follows: + // We need to lock the composition, as we will proceed modifying our internal state. The tricky part is when we release the lock + // Due to the fact that some actions will take place AFTER we leave this method, we need to KEEP THAT LOCK HELD until the transation is commiited or rolled back + // This is the reason we CAN'T use "using here. + // Instead, if the transaction is present we will queue up the release of the lock, otherwise we will release it when we exit this method + // We add the "release" lock to BOTH Commit and Revert queues, because they are mutually exclusive, and we need to release the lock regardless. + + // This will take the lock, if necesary + IDisposable compositionLockHolder = this._lock.IsThreadSafe ? this._lock.LockComposition() : null; + bool compositionLockTaken = (compositionLockHolder != null); + try + { + // revert actions are processed in the reverse order, so we have to add the "release lock" action now + if (compositionLockTaken && (atomicComposition != null)) + { + atomicComposition.AddRevertAction(() => compositionLockHolder.Dispose()); + } + + var partManager = GetPartManager(part, true); + var result = TryPreviewImportsStateMachine(partManager, part, atomicComposition); + result.ThrowOnErrors(atomicComposition); + + StartSatisfyingImports(partManager, atomicComposition); + + // Add the "release lock" to the commit actions + if (compositionLockTaken && (atomicComposition != null)) + { + atomicComposition.AddCompleteAction(() => compositionLockHolder.Dispose()); + } + } + finally + { + // We haven't updated the queues, so we can release the lock now + if (compositionLockTaken && (atomicComposition == null)) + { + compositionLockHolder.Dispose(); + } + } + } + + /// <summary> + /// Satisfies the imports of the specified composable part. If the satisfy succeeds then + /// the <see cref="ImportEngine"/> also enforces that changes to exports in the source + /// provider will not break any of the required imports. If this enforcement needs to be + /// lifted for this part then <see cref="ReleaseImports"/> needs to be called for this + /// <see cref="ComposablePart"/>. + /// </summary> + /// <param name="part"> + /// The <see cref="ComposablePart"/> to set the imports. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="part"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ImportEngine"/> has been disposed of. + /// </exception> + public void SatisfyImports(ComposablePart part) + { + this.ThrowIfDisposed(); + + Requires.NotNull(part, "part"); + + // NOTE : the following two calls use the state lock + PartManager partManager = this.GetPartManager(part, true); + if (partManager.State == ImportState.Composed) + { + return; + } + + using (this._lock.LockComposition()) + { + var result = TrySatisfyImports(partManager, part, true); + result.ThrowOnErrors(); // throw CompositionException not ChangeRejectedException + } + } + + /// <summary> + /// Sets the imports of the specified composable part exactly once and they will not + /// ever be recomposed. + /// </summary> + /// <param name="part"> + /// The <see cref="ComposablePart"/> to set the imports. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="part"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ICompositionService"/> has been disposed of. + /// </exception> + public void SatisfyImportsOnce(ComposablePart part) + { + this.ThrowIfDisposed(); + + Requires.NotNull(part, "part"); + + // NOTE : the following two calls use the state lock + PartManager partManager = this.GetPartManager(part, true); + if (partManager.State == ImportState.Composed) + { + return; + } + + using (this._lock.LockComposition()) + { + var result = TrySatisfyImports(partManager, part, false); + result.ThrowOnErrors(); // throw CompositionException not ChangeRejectedException + } + } + + /// <summary> + /// Removes any state stored in the <see cref="ImportEngine"/> for the associated + /// <see cref="ComposablePart"/> and releases all the <see cref="Export"/>s used to + /// satisfy the imports on the <see cref="ComposablePart"/>. + /// + /// Also removes the enforcement for changes that would break a required import on + /// <paramref name="part"/>. + /// </summary> + /// <param name="part"> + /// The <see cref="ComposablePart"/> to release the imports on. + /// </param> + /// <param name="atomicComposition"> + /// The <see cref="AtomicComposition"/> that the release imports is running under. + /// </param> + public void ReleaseImports(ComposablePart part, AtomicComposition atomicComposition) + { + this.ThrowIfDisposed(); + + Requires.NotNull(part, "part"); + + using (this._lock.LockComposition()) + { + PartManager partManager = this.GetPartManager(part, false); + if (partManager != null) + { + this.StopSatisfyingImports(partManager, atomicComposition); + } + } + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and - optionally - managed resources + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (!this._isDisposed) + { + bool disposeLock = false; + ExportProvider sourceProviderToUnsubscribeFrom = null; + using (this._lock.LockStateForWrite()) + { + if (!this._isDisposed) + { + sourceProviderToUnsubscribeFrom = this._sourceProvider; + this._sourceProvider = null; + this._recompositionManager = null; + this._partManagers = null; + this._isDisposed = true; + disposeLock = true; + } + } + + if (sourceProviderToUnsubscribeFrom != null) + { + sourceProviderToUnsubscribeFrom.ExportsChanging -= this.OnExportsChanging; + } + + if (disposeLock) + { + this._lock.Dispose(); + } + } + } + } + + private CompositionResult TryPreviewImportsStateMachine(PartManager partManager, + ComposablePart part, AtomicComposition atomicComposition) + { + var result = CompositionResult.SucceededResult; + + if (partManager.State == ImportState.ImportsPreviewing) + { + // We shouldn't nomally ever hit this case but if we do + // then we should just error with a cycle error. + return new CompositionResult(ErrorBuilder.CreatePartCycle(part)); + } + + // Transition from NoImportsStatisified to ImportsPreviewed + if (partManager.State == ImportState.NoImportsSatisfied) + { + partManager.State = ImportState.ImportsPreviewing; + + var requiredImports = part.ImportDefinitions.Where(IsRequiredImportForPreview); + + // If this atomicComposition gets rolledback for any reason we need to reset our state + atomicComposition.AddRevertActionAllowNull(() => partManager.State = ImportState.NoImportsSatisfied); + + result = result.MergeResult( + this.TrySatisfyImportSubset(partManager, requiredImports, atomicComposition)); + + if (!result.Succeeded) + { + partManager.State = ImportState.NoImportsSatisfied; + return result; + } + + partManager.State = ImportState.ImportsPreviewed; + } + + return result; + } + + private CompositionResult TrySatisfyImportsStateMachine(PartManager partManager, ComposablePart part) + { + var result = CompositionResult.SucceededResult; + + while (partManager.State < ImportState.Composed) + { + var previousState = partManager.State; + + switch (partManager.State) + { + // "ed" states which represent a some sort of steady state and will + // attempt to do a state transition + case ImportState.NoImportsSatisfied: + case ImportState.ImportsPreviewed: + { + partManager.State = ImportState.PreExportImportsSatisfying; + + var prereqImports = part.ImportDefinitions.Where(import => import.IsPrerequisite); + result = result.MergeResult( + this.TrySatisfyImportSubset(partManager, prereqImports, null)); + + partManager.State = ImportState.PreExportImportsSatisfied; + break; + } + case ImportState.PreExportImportsSatisfied: + { + partManager.State = ImportState.PostExportImportsSatisfying; + + var requiredImports = part.ImportDefinitions.Where(import => !import.IsPrerequisite); + + result = result.MergeResult( + this.TrySatisfyImportSubset(partManager, requiredImports, null)); + + partManager.State = ImportState.PostExportImportsSatisfied; + break; + } + case ImportState.PostExportImportsSatisfied: + { + partManager.State = ImportState.ComposedNotifying; + + partManager.ClearSavedImports(); + result = result.MergeResult(partManager.TryOnComposed()); + + partManager.State = ImportState.Composed; + break; + } + + + // "ing" states which represent some sort of cycle + // These state should always return, error or not, instead of breaking + case ImportState.ImportsPreviewing: + { + // We shouldn't nomally ever hit this case but if we do + // then we should just error with a cycle error. + return new CompositionResult(ErrorBuilder.CreatePartCycle(part)); + } + case ImportState.PreExportImportsSatisfying: + case ImportState.PostExportImportsSatisfying: + { + if (InPrerequisiteLoop()) + { + return result.MergeError(ErrorBuilder.CreatePartCycle(part)); + } + // Cycles in post export imports are allowed so just return in that case + return result; + } + case ImportState.ComposedNotifying: + { + // We are currently notifying so don't notify again just return + return result; + } + } + + // if an error occured while doing a state transition + if (!result.Succeeded) + { + // revert to the previous state and return the error + partManager.State = previousState; + return result; + } + } + return result; + } + + private CompositionResult TrySatisfyImports(PartManager partManager, ComposablePart part, bool shouldTrackImports) + { + Assumes.NotNull(part); + + var result = CompositionResult.SucceededResult; + + // get out if the part is already composed + if (partManager.State == ImportState.Composed) + { + return result; + } + + // Track number of recursive iterations and throw an exception before the stack + // fills up and debugging the root cause becomes tricky + if (this._recursionStateStack.Count >= MaximumNumberOfCompositionIterations) + { + return result.MergeError( + ErrorBuilder.ComposeTookTooManyIterations(MaximumNumberOfCompositionIterations)); + } + + // Maintain the stack to detect whether recursive loops cross prerequisites + this._recursionStateStack.Push(partManager); + try + { + result = result.MergeResult( + TrySatisfyImportsStateMachine(partManager, part)); + } + finally + { + this._recursionStateStack.Pop(); + } + + if (shouldTrackImports) + { + StartSatisfyingImports(partManager, null); + } + + return result; + } + + private CompositionResult TrySatisfyImportSubset(PartManager partManager, + IEnumerable<ImportDefinition> imports, AtomicComposition atomicComposition) + { + CompositionResult result = CompositionResult.SucceededResult; + + var part = partManager.Part; + foreach (ImportDefinition import in imports) + { + var exports = partManager.GetSavedImport(import); + + if (exports == null) + { + CompositionResult<IEnumerable<Export>> exportsResult = TryGetExports( + this._sourceProvider, part, import, atomicComposition); + + if (!exportsResult.Succeeded) + { + result = result.MergeResult(exportsResult.ToResult()); + continue; + } + exports = exportsResult.Value.AsArray(); + } + + if (atomicComposition == null) + { + result = result.MergeResult( + partManager.TrySetImport(import, exports)); + } + else + { + partManager.SetSavedImport(import, exports, atomicComposition); + } + } + return result; + } + + private void OnExportsChanging(object sender, ExportsChangeEventArgs e) + { + CompositionResult result = CompositionResult.SucceededResult; + + // Prepare for the recomposition effort by minimizing the amount of work we'll have to do later + AtomicComposition atomicComposition = e.AtomicComposition; + + IEnumerable<PartManager> affectedParts = this._recompositionManager.GetAffectedParts(e.ChangedContractNames); + + // When in a atomicComposition account for everything that isn't yet reflected in the + // index + if (atomicComposition != null) + { + EngineContext engineContext; + if (atomicComposition.TryGetValue(this, out engineContext)) + { + // always added the new part managers to see if they will also be + // affected by these changes + affectedParts = affectedParts.ConcatAllowingNull(engineContext.GetAddedPartManagers()) + .Except(engineContext.GetRemovedPartManagers()); + } + } + + var changedExports = e.AddedExports.ConcatAllowingNull(e.RemovedExports); + + foreach (var partManager in affectedParts) + { + result = result.MergeResult(this.TryRecomposeImports(partManager, changedExports, atomicComposition)); + } + + result.ThrowOnErrors(atomicComposition); + } + + private CompositionResult TryRecomposeImports(PartManager partManager, + IEnumerable<ExportDefinition> changedExports, AtomicComposition atomicComposition) + { + var result = CompositionResult.SucceededResult; + + switch (partManager.State) + { + case ImportState.ImportsPreviewed: + case ImportState.Composed: + // Validate states to continue. + break; + + default: + { + // All other states are invalid and for recomposition. + return new CompositionResult(ErrorBuilder.InvalidStateForRecompposition(partManager.Part)); + } + } + + var affectedImports = RecompositionManager.GetAffectedImports(partManager.Part, changedExports); + bool partComposed = (partManager.State == ImportState.Composed); + + bool recomposedImport = false; + foreach (var import in affectedImports) + { + result = result.MergeResult( + TryRecomposeImport(partManager, partComposed, import, atomicComposition)); + + recomposedImport = true; + } + + // Knowing that the part has already been composed before and that the only possible + // changes are to recomposable imports, we can safely go ahead and do this now or + // schedule it for later + if (result.Succeeded && recomposedImport && partComposed) + { + if (atomicComposition == null) + { + result = result.MergeResult(partManager.TryOnComposed()); + } + else + { + atomicComposition.AddCompleteAction(() => partManager.TryOnComposed().ThrowOnErrors()); + } + } + + return result; + } + + private CompositionResult TryRecomposeImport(PartManager partManager, bool partComposed, + ImportDefinition import, AtomicComposition atomicComposition) + { + if (partComposed && !import.IsRecomposable) + { + return new CompositionResult(ErrorBuilder.PreventedByExistingImport(partManager.Part, import)); + } + + // During recomposition you must always requery with the new atomicComposition you cannot use any + // cached value in the part manager + var exportsResult = TryGetExports(this._sourceProvider, partManager.Part, import, atomicComposition); + if (!exportsResult.Succeeded) + { + return exportsResult.ToResult(); + } + var exports = exportsResult.Value.AsArray(); + + if (partComposed) + { + // Knowing that the part has already been composed before and that the only possible + // changes are to recomposable imports, we can safely go ahead and do this now or + // schedule it for later + if (atomicComposition == null) + { + return partManager.TrySetImport(import, exports); + } + else + { + atomicComposition.AddCompleteAction(() => partManager.TrySetImport(import, exports).ThrowOnErrors()); + } + } + else + { + partManager.SetSavedImport(import, exports, atomicComposition); + } + + return CompositionResult.SucceededResult; + } + + private void StartSatisfyingImports(PartManager partManager, AtomicComposition atomicComposition) + { + // When not running in a atomicCompositional state, schedule reindexing after ensuring + // that this isn't a redundant addition + if (atomicComposition == null) + { + if (!partManager.TrackingImports) + { + partManager.TrackingImports = true; + this._recompositionManager.AddPartToIndex(partManager); + } + } + else + { + // While in a atomicCompositional state use a less efficient but effective means + // of achieving the same results + GetEngineContext(atomicComposition).AddPartManager(partManager); + } + } + + private void StopSatisfyingImports(PartManager partManager, AtomicComposition atomicComposition) + { + // When not running in a atomicCompositional state, schedule reindexing after ensuring + // that this isn't a redundant removal + if (atomicComposition == null) + { + this._partManagers.Remove(partManager.Part); + + // Take care of lifetime requirements + partManager.DisposeAllDependencies(); + + if (partManager.TrackingImports) + { + partManager.TrackingImports = false; + this._recompositionManager.AddPartToUnindex(partManager); + } + } + else + { + // While in a atomicCompositional state use a less efficient but effective means + // of achieving the same results + GetEngineContext(atomicComposition).RemovePartManager(partManager); + } + } + + private PartManager GetPartManager(ComposablePart part, bool createIfNotpresent) + { + PartManager partManager = null; + using (this._lock.LockStateForRead()) + { + if (this._partManagers.TryGetValue(part, out partManager)) + { + return partManager; + } + } + + if (createIfNotpresent) + { + using (this._lock.LockStateForWrite()) + { + if (!this._partManagers.TryGetValue(part, out partManager)) + { + partManager = new PartManager(this, part); + this._partManagers.Add(part, partManager); + } + } + } + return partManager; + } + + + private EngineContext GetEngineContext(AtomicComposition atomicComposition) + { + Assumes.NotNull(atomicComposition); + + EngineContext engineContext; + if (!atomicComposition.TryGetValue(this, true, out engineContext)) + { + EngineContext parentContext; + atomicComposition.TryGetValue(this, false, out parentContext); + engineContext = new EngineContext(this, parentContext); + atomicComposition.SetValue(this, engineContext); + atomicComposition.AddCompleteAction(engineContext.Complete); + } + return engineContext; + } + + private bool InPrerequisiteLoop() + { + PartManager firstPart = this._recursionStateStack.First(); + PartManager lastPart = null; + + foreach (PartManager testPart in this._recursionStateStack.Skip(1)) + { + if (testPart.State == ImportState.PreExportImportsSatisfying) + { + return true; + } + + if (testPart == firstPart) + { + lastPart = testPart; + break; + } + } + + // This should only be called when a loop has been detected - so it should always be on the stack + Assumes.IsTrue(lastPart == firstPart); + return false; + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + private static CompositionResult<IEnumerable<Export>> TryGetExports(ExportProvider provider, + ComposablePart part, ImportDefinition definition, AtomicComposition atomicComposition) + { + try + { + var exports = provider.GetExports(definition, atomicComposition).AsArray(); + return new CompositionResult<IEnumerable<Export>>(exports); + } + catch (ImportCardinalityMismatchException ex) + { + // Either not enough or too many exports that match the definition + CompositionException exception = new CompositionException(ErrorBuilder.CreateImportCardinalityMismatch(ex, definition)); + + return new CompositionResult<IEnumerable<Export>>( + ErrorBuilder.CreatePartCannotSetImport(part, definition, exception)); + } + } + + internal static bool IsRequiredImportForPreview(ImportDefinition import) + { + return import.Cardinality == ImportCardinality.ExactlyOne; + } + + // Ordering of this enum is important so be sure to use caution if you + // try to reorder them. + private enum ImportState + { + NoImportsSatisfied = 0, + ImportsPreviewing = 1, + ImportsPreviewed = 2, + PreExportImportsSatisfying = 3, + PreExportImportsSatisfied = 4, + PostExportImportsSatisfying = 5, + PostExportImportsSatisfied = 6, + ComposedNotifying = 7, + Composed = 8, + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportSourceImportDefinitionHelpers.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportSourceImportDefinitionHelpers.cs new file mode 100644 index 00000000000..d00a3eee547 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ImportSourceImportDefinitionHelpers.cs @@ -0,0 +1,118 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq.Expressions; +using Microsoft.Internal; +using System.Diagnostics.Contracts; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.Hosting +{ + + internal static class ImportSourceImportDefinitionHelpers + { + public static ImportDefinition RemoveImportSource(this ImportDefinition definition) + { + var contractBasedDefinition = definition as ContractBasedImportDefinition; + if(contractBasedDefinition == null) + { + return definition; + } + else + { + return new NonImportSourceImportDefinition(contractBasedDefinition); + } + } + + internal class NonImportSourceImportDefinition : ContractBasedImportDefinition + { + private ContractBasedImportDefinition _sourceDefinition; + private IDictionary<string, object> _metadata; + + public NonImportSourceImportDefinition(ContractBasedImportDefinition sourceDefinition) + { + Assumes.NotNull(sourceDefinition); + this._sourceDefinition = sourceDefinition; + this._metadata = null; + } + + public override string ContractName + { + get { return this._sourceDefinition.ContractName; } + } + + public override IDictionary<string, object> Metadata + { + get + { + Contract.Ensures(Contract.Result<IDictionary<string, object>>() != null); + + var reply = this._metadata; + if(reply == null) + { + reply = new Dictionary<string, object> (this._sourceDefinition.Metadata); + reply.Remove(CompositionConstants.ImportSourceMetadataName); + this._metadata = reply; + } + + return reply; + } + } + + public override ImportCardinality Cardinality + { + get { return this._sourceDefinition.Cardinality; } + } + + public override Expression<Func<ExportDefinition, bool>> Constraint + { + get { return this._sourceDefinition.Constraint; } + } + + public override bool IsPrerequisite + { + get { return this._sourceDefinition.IsPrerequisite; } + } + + public override bool IsRecomposable + { + get { return this._sourceDefinition.IsRecomposable; } + } + + public override bool IsConstraintSatisfiedBy(ExportDefinition exportDefinition) + { + Requires.NotNull(exportDefinition, "exportDefinition"); + + return this._sourceDefinition.IsConstraintSatisfiedBy(exportDefinition); + } + + public override string ToString() + { + return this._sourceDefinition.ToString(); + } + + public override string RequiredTypeIdentity + { + get { return this._sourceDefinition.RequiredTypeIdentity; } + } + + public override IEnumerable<KeyValuePair<string, Type>> RequiredMetadata + { + get + { + return this._sourceDefinition.RequiredMetadata; + } + } + + public override CreationPolicy RequiredCreationPolicy + { + get { return this._sourceDefinition.RequiredCreationPolicy; } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ScopingExtensions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ScopingExtensions.cs new file mode 100644 index 00000000000..f0d0e558773 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ScopingExtensions.cs @@ -0,0 +1,148 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics; +using System.Collections.Generic; +using Microsoft.Internal; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.Hosting +{ + public static class ScopingExtensions + { + /// <summary> + /// Determines whether the specified part exports the specified contract. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="contractName">Name of the contract.</param> + /// <returns> + /// <c>true</c> if the specified part exports the specified contract; otherwise, <c>false</c>. + /// </returns> + public static bool Exports(this ComposablePartDefinition part, string contractName) + { + Requires.NotNull(part, "part"); + Requires.NotNull(contractName, "contractName"); + + foreach (ExportDefinition export in part.ExportDefinitions) + { + if (StringComparers.ContractName.Equals(contractName, export.ContractName)) + { + return true; + } + } + return false; + } + + /// <summary> + /// Determines whether the specified part imports the specified contract. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="contractName">Name of the contract.</param> + /// <returns> + /// <c>true</c> if the specified part imports the specified contract; otherwise, <c>false</c>. + /// </returns> + public static bool Imports(this ComposablePartDefinition part, string contractName) + { + Requires.NotNull(part, "part"); + Requires.NotNull(contractName, "contractName"); + + foreach (ImportDefinition import in part.ImportDefinitions) + { + if (StringComparers.ContractName.Equals(contractName, import.ContractName)) + { + return true; + } + } + + return false; + } + + /// <summary> + /// Determines whether the specified part imports the specified contract with the given cardinality. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="contractName">Name of the contract.</param> + /// <param name="importCardinality">The import cardinality.</param> + /// <returns> + /// <c>true</c> if the specified part imports the specified contract with the given cardinality; otherwise, <c>false</c>. + /// </returns> + public static bool Imports(this ComposablePartDefinition part, string contractName, ImportCardinality importCardinality) + { + Requires.NotNull(part, "part"); + Requires.NotNull(contractName, "contractName"); + + foreach (ImportDefinition import in part.ImportDefinitions) + { + if (StringComparers.ContractName.Equals(contractName, import.ContractName) && (import.Cardinality == importCardinality)) + { + return true; + } + } + + return false; + } + + + /// <summary> + /// Determines whether the part contains a metadata entry with the specified key. + /// </summary> + /// <param name="part">The part.</param> + /// <param name="key">The key.</param> + /// <returns> + /// <c>true</c> if the part contains a metadata entry with the specified key; otherwise, <c>false</c>. + /// </returns> + public static bool ContainsPartMetadataWithKey(this ComposablePartDefinition part, string key) + { + Requires.NotNull(part, "part"); + Requires.NotNull(key, "key"); + + return part.Metadata.ContainsKey(key); + } + + /// <summary> + /// Determines whether the specified part contains a metadata entry with the specified key and value. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="part">The part.</param> + /// <param name="key">The key.</param> + /// <param name="value">The value.</param> + /// <returns> + /// <c>true</c> the specified part contains a metadata entry with the specified key and value; otherwise, <c>false</c>. + /// </returns> + public static bool ContainsPartMetadata<T>(this ComposablePartDefinition part, string key, T value) + { + Requires.NotNull(part, "part"); + Requires.NotNull(key, "key"); + + object untypedValue = null; + if (part.Metadata.TryGetValue(key, out untypedValue)) + { + if (value == null) + { + return (untypedValue == null); + } + else + { + return value.Equals(untypedValue); + } + } + + return false; + } + + /// <summary> + /// Filters the specified catalog. + /// </summary> + /// <param name="catalog">The catalog.</param> + /// <param name="filter">The filter.</param> + /// <returns></returns> + public static FilteredCatalog Filter(this ComposablePartCatalog catalog, Func<ComposablePartDefinition, bool> filter) + { + Requires.NotNull(catalog, "catalog"); + Requires.NotNull(filter, "filter"); + + return new FilteredCatalog(catalog, filter); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/TypeCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/TypeCatalog.cs new file mode 100644 index 00000000000..1bc94232b93 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/TypeCatalog.cs @@ -0,0 +1,415 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.AttributedModel; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Hosting +{ + /// <summary> + /// An immutable ComposablePartCatalog created from a type array or a list of managed types. This class is threadsafe. + /// It is Disposable. + /// </summary> + [DebuggerTypeProxy(typeof(ComposablePartCatalogDebuggerProxy))] + public class TypeCatalog : ComposablePartCatalog, ICompositionElement + { + private readonly object _thisLock = new object(); + private Type[] _types = null; + private volatile List<ComposablePartDefinition> _parts; + private volatile bool _isDisposed = false; + private readonly ICompositionElement _definitionOrigin; + private readonly Lazy<IDictionary<string, List<ComposablePartDefinition>>> _contractPartIndex; + + /// <summary> + /// Initializes a new instance of the <see cref="TypeCatalog"/> class + /// with the specified types. + /// </summary> + /// <param name="types"> + /// An <see cref="Array"/> of attributed <see cref="Type"/> objects to add to the + /// <see cref="TypeCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="types"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="types"/> contains an element that is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="types"/> contains an element that was loaded in the Reflection-only context. + /// </exception> + public TypeCatalog(params Type[] types) : this((IEnumerable<Type>)types) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeCatalog"/> class + /// with the specified types. + /// </summary> + /// <param name="types"> + /// An <see cref="IEnumerable{T}"/> of attributed <see cref="Type"/> objects to add + /// to the <see cref="TypeCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="types"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="types"/> contains an element that is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="types"/> contains an element that was loaded in the reflection-only context. + /// </exception> + public TypeCatalog(IEnumerable<Type> types) + { + Requires.NotNull(types, "types"); + + InitializeTypeCatalog(types); + + this._definitionOrigin = this; + this._contractPartIndex = new Lazy<IDictionary<string, List<ComposablePartDefinition>>>(this.CreateIndex, true); + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeCatalog"/> class + /// with the specified types. + /// </summary> + /// <param name="types"> + /// An <see cref="IEnumerable{T}"/> of attributed <see cref="Type"/> objects to add + /// to the <see cref="TypeCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="types"/> is <see langword="null"/>. + /// </exception> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="types"/> contains an element that is <see langword="null"/>. + /// </exception> + public TypeCatalog(IEnumerable<Type> types, ICompositionElement definitionOrigin) + { + Requires.NotNull(types, "types"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + InitializeTypeCatalog(types); + + this._definitionOrigin = definitionOrigin; + this._contractPartIndex = new Lazy<IDictionary<string, List<ComposablePartDefinition>>>(this.CreateIndex, true); + } + +#if FEATURE_REFLECTIONCONTEXT + /// <summary> + /// Initializes a new instance of the <see cref="TypeCatalog"/> class + /// with the specified types. + /// </summary> + /// <param name="types"> + /// An <see cref="IEnumerable{T}"/> of attributed <see cref="Type"/> objects to add + /// to the <see cref="TypeCatalog"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="types"/> is <see langword="null"/>. + /// </exception> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <exception cref="ArgumentException"> + /// <paramref name="types"/> contains an element that is <see langword="null"/>. + /// </exception> + public TypeCatalog(IEnumerable<Type> types, ReflectionContext reflectionContext) + { + Requires.NotNull(types, "types"); + Requires.NotNull(reflectionContext, "reflectionContext"); + + InitializeTypeCatalog(types, reflectionContext); + + this._definitionOrigin = this; + this._contractPartIndex = new Lazy<IDictionary<string, List<ComposablePartDefinition>>>(this.CreateIndex, true); + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeCatalog"/> class + /// with the specified types. + /// </summary> + /// <param name="types"> + /// An <see cref="IEnumerable{T}"/> of attributed <see cref="Type"/> objects to add + /// to the <see cref="TypeCatalog"/>. + /// </param> + /// <param name="reflectionContext"> + /// The <see cref="ReflectionContext"/> a context used by the catalog when + /// interpreting the types to inject attributes into the type definition. + /// </param> + /// <param name="definitionOrigin"> + /// The <see cref="ICompositionElement"/> CompositionElement used by Diagnostics to identify the source for parts. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="types"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="types"/> contains an element that is <see langword="null"/>. + /// </exception> + public TypeCatalog(IEnumerable<Type> types, ReflectionContext reflectionContext, ICompositionElement definitionOrigin) + { + Requires.NotNull(types, "types"); + Requires.NotNull(reflectionContext, "reflectionContext"); + Requires.NotNull(definitionOrigin, "definitionOrigin"); + + InitializeTypeCatalog(types, reflectionContext); + + this._definitionOrigin = definitionOrigin; + this._contractPartIndex = new Lazy<IDictionary<string, List<ComposablePartDefinition>>>(this.CreateIndex, true); + } + + private void InitializeTypeCatalog(IEnumerable<Type> types, ReflectionContext reflectionContext) + { + var typesList = new List<Type>(); + foreach(var type in types) + { + if (type == null) + { + throw ExceptionBuilder.CreateContainsNullElement("types"); + } + + if (type.Assembly.ReflectionOnly) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_ElementReflectionOnlyType, "types"), "types"); + } + + var typeInfo = type.GetTypeInfo(); + var lclType = (reflectionContext != null) ? reflectionContext.MapType(typeInfo) : typeInfo; + + // It is valid for the reflectionContext to delete types by mapping them to null + if(lclType != null) + { + // The final mapped type may be activated so we check to see if it is in a reflect only assembly + if (lclType.Assembly.ReflectionOnly) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_ReflectionContextReturnsReflectionOnlyType, "reflectionContext"), "reflectionContext"); + } + + + typesList.Add(lclType); + } + } + this._types = typesList.ToArray(); + } +#endif //FEATURE_REFLECTIONCONTEXT + + private void InitializeTypeCatalog(IEnumerable<Type> types) + { + foreach(var type in types) + { + if (type == null) + { + throw ExceptionBuilder.CreateContainsNullElement("types"); + } +#if FEATURE_REFLECTIONONLY + else if (type.Assembly.ReflectionOnly) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_ElementReflectionOnlyType, "types"), "types"); + } +#endif //FEATURE_REFLECTIONONLY + } + this._types = types.ToArray(); + } + + + public override IEnumerator<ComposablePartDefinition> GetEnumerator() + { + this.ThrowIfDisposed(); + return this.PartsInternal.GetEnumerator(); + } + + /// <summary> + /// Gets the display name of the type catalog. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a human-readable display name of the <see cref="TypeCatalog"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + /// <summary> + /// Gets the composition element from which the type catalog originated. + /// </summary> + /// <value> + /// This property always returns <see langword="null"/>. + /// </value> + [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] + ICompositionElement ICompositionElement.Origin + { + get { return null; } + } + + private IEnumerable<ComposablePartDefinition> PartsInternal + { + get + { + if (this._parts == null) + { + lock (this._thisLock) + { + if (this._parts == null) + { + Assumes.NotNull(this._types); + + var collection = new List<ComposablePartDefinition>(); + foreach (Type type in this._types) + { + var definition = AttributedModelDiscovery.CreatePartDefinitionIfDiscoverable(type, _definitionOrigin); + if (definition != null) + { + collection.Add(definition); + } + } + Thread.MemoryBarrier(); + + this._types = null; + this._parts = collection; + } + } + } + + return this._parts; + } + } + + internal override IEnumerable<ComposablePartDefinition> GetCandidateParts(ImportDefinition definition) + { + Assumes.NotNull(definition); + + string contractName = definition.ContractName; + if (string.IsNullOrEmpty(contractName)) + { + return this.PartsInternal; + } + + string genericContractName = definition.Metadata.GetValue<string>(CompositionConstants.GenericContractMetadataName); + + List<ComposablePartDefinition> nonGenericMatches = this.GetCandidateParts(contractName); + List<ComposablePartDefinition> genericMatches = this.GetCandidateParts(genericContractName); + + return nonGenericMatches.ConcatAllowingNull(genericMatches); + } + + private List<ComposablePartDefinition> GetCandidateParts(string contractName) + { + if (contractName == null) + { + return null; + } + + List<ComposablePartDefinition> contractCandidateParts = null; + this._contractPartIndex.Value.TryGetValue(contractName, out contractCandidateParts); + return contractCandidateParts; + } + + private IDictionary<string, List<ComposablePartDefinition>> CreateIndex() + { + Dictionary<string, List<ComposablePartDefinition>> index = new Dictionary<string, List<ComposablePartDefinition>>(StringComparers.ContractName); + + foreach (var part in this.PartsInternal) + { + foreach (string contractName in part.ExportDefinitions.Select(export => export.ContractName).Distinct()) + { + List<ComposablePartDefinition> contractParts = null; + if (!index.TryGetValue(contractName, out contractParts)) + { + contractParts = new List<ComposablePartDefinition>(); + index.Add(contractName, contractParts); + } + contractParts.Add(part); + } + } + return index; + } + + /// <summary> + /// Returns a string representation of the type catalog. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the string representation of the <see cref="TypeCatalog"/>. + /// </returns> + public override string ToString() + { + return this.GetDisplayName(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + this._isDisposed = true; + } + + base.Dispose(disposing); + } + + private string GetDisplayName() + { + return String.Format(CultureInfo.CurrentCulture, + Strings.TypeCatalog_DisplayNameFormat, + this.GetType().Name, + this.GetTypesDisplay()); + } + + private string GetTypesDisplay() + { + int count = this.PartsInternal.Count(); + if (count == 0) + { + return Strings.TypeCatalog_Empty; + } + + const int displayCount = 2; + StringBuilder builder = new StringBuilder(); + foreach (ReflectionComposablePartDefinition definition in this.PartsInternal.Take(displayCount)) + { + if (builder.Length > 0) + { + builder.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator); + builder.Append(" "); + } + + builder.Append(definition.GetPartType().GetDisplayName()); + } + + if (count > displayCount) + { // Add an elipse to indicate that there + // are more types than actually listed + builder.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator); + builder.Append(" ..."); + } + + return builder.ToString(); + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/IAttributedImport.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/IAttributedImport.cs new file mode 100644 index 00000000000..39158c7fdab --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/IAttributedImport.cs @@ -0,0 +1,18 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + internal interface IAttributedImport + { + string ContractName { get; } + Type ContractType { get; } + bool AllowRecomposition { get; } + CreationPolicy RequiredCreationPolicy { get; } + ImportCardinality Cardinality { get; } + ImportSource Source { get; } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ICompositionService.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ICompositionService.cs new file mode 100644 index 00000000000..fac6448e957 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ICompositionService.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.Contracts; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Provides methods for composing <see cref="ComposablePart"/> objects. + /// </summary> +#if CONTRACTS_FULL + [ContractClass(typeof(ICompositionServiceContract))] +#endif + public interface ICompositionService + { + /// <summary> + /// Sets the imports of the specified composable part exactly once and they will not + /// ever be recomposed. + /// </summary> + /// <param name="part"> + /// The <see cref="ComposablePart"/> to set the imports. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="part"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ICompositionService"/> has been disposed of. + /// </exception> + void SatisfyImportsOnce(ComposablePart part); + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/IPartImportsSatisfiedNotification.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/IPartImportsSatisfiedNotification.cs new file mode 100644 index 00000000000..7969e0cb7cf --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/IPartImportsSatisfiedNotification.cs @@ -0,0 +1,12 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition +{ + public interface IPartImportsSatisfiedNotification + { + void OnImportsSatisfied(); + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportAttribute.cs new file mode 100644 index 00000000000..48f2aea8fc5 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportAttribute.cs @@ -0,0 +1,197 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that a property, field, or parameter imports a particular export. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes")] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, + AllowMultiple = false, Inherited = false)] + public class ImportAttribute : Attribute, IAttributedImport + { + /// <summary> + /// Initializes a new instance of the <see cref="ImportAttribute"/> class, importing the + /// export with the default contract name. + /// </summary> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property, field, + /// or parameter type that this is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ImportAttribute() + : this((string)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportAttribute"/> class, importing the + /// export with the contract name derived from the specified type. + /// </summary> + /// <param name="contractType"> + /// A <see cref="Type"/> of which to derive the contract name of the export to import, or + /// <see langword="null"/> to use the default contract name. + /// </param> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on + /// <paramref name="contractType"/>. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property, field, + /// or parameter type that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ImportAttribute(Type contractType) + : this((string)null, contractType) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportAttribute"/> class, importing the + /// export with the specified contract name. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the export to import, or + /// <see langword="null"/> or an empty string ("") to use the default contract name. + /// </param> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property, field, + /// or parameter type that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ImportAttribute(string contractName) + : this(contractName, (Type)null) + { + } + + public ImportAttribute(string contractName, Type contractType) + { + this.ContractName = contractName; + this.ContractType = contractType; + } + + /// <summary> + /// Gets the contract name of the export to import. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the contract name of the export to import. The + /// default value is an empty string (""). + /// </value> + public string ContractName { get; private set; } + + /// <summary> + /// Get the contract type of the export to import. + /// </summary> + /// <value> + /// A <see cref="Type"/> of the export that this import is expecting. The default value is + /// <see langword="null"/> which means that the type will be obtained by looking at the type on + /// the member that this import is attached to. If the type is <see cref="object"/> then the + /// importer is delaring they can accept any exported type. + /// </value> + public Type ContractType { get; private set; } + + /// <summary> + /// Gets or sets a value indicating whether the property, field or parameter will be set + /// to its type's default value when an export with the contract name is not present in + /// the container. + /// </summary> + /// <value> + /// <see langword="true"/> if the property, field or parameter will be set + /// its type's default value when an export with the <see cref="ContractName"/> is not + /// present in the <see cref="CompositionContainer"/>; otherwise, <see langword="false"/>. + /// The default value is <see langword="false"/>. + /// </value> + /// <remarks> + /// <para> + /// The default value of a property's, field's or parameter's type is + /// <see langword="null"/> for reference types and 0 for numeric value types. For + /// other value types, the default value will be each field of the value type + /// initialized to zero, if the field is a value type or <see langword="null"/> if + /// the field is a reference type. + /// </para> + /// </remarks> + public bool AllowDefault { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether the property or field will be recomposed + /// when exports that provide the same contract that this import expects, have changed + /// in the container. + /// </summary> + /// <value> + /// <see langword="true"/> if the property or field allows for recomposition when exports + /// that provide the same <see cref="ContractName"/> are added or removed from the + /// <see cref="CompositionContainer"/>; otherwise, <see langword="false"/>. + /// The default value is <see langword="false"/>. + /// </value> + public bool AllowRecomposition { get; set; } + + /// <summary> + /// Gets or sets a value indicating that the importer requires a specific + /// <see cref="CreationPolicy"/> for the exports used to satisfy this import. T + /// </summary> + /// <value> + /// <see cref="CreationPolicy.Any"/> - default value, used if the importer doesn't + /// require a specific <see cref="CreationPolicy"/>. + /// + /// <see cref="CreationPolicy.Shared"/> - Requires that all exports used should be shared + /// by everyone in the container. + /// + /// <see cref="CreationPolicy.NonShared"/> - Requires that all exports used should be + /// non-shared in a container and thus everyone gets their own instance. + /// </value> + public CreationPolicy RequiredCreationPolicy { get; set; } + + /// <summary> + /// Gets or sets a value indicating that the importer indicating that the composition engine + /// either should satisfy exports from the local or no local scope. + /// </summary> + /// <value> + /// <see cref="ImportSource.Any"/> - indicates that importer does not + /// require a specific satisfaction scope"/>. + /// + /// <see cref="ImportSource.Local"/> - indicates the importer requires satisfaction to be + /// from the current container. + /// + /// <see cref="ImportSource.NonLocal"/> - indicates the importer requires satisfaction to be + /// from one of the ancestor containers. + /// </value> + public ImportSource Source { get; set; } + + ImportCardinality IAttributedImport.Cardinality + { + get + { + if (this.AllowDefault == true) + { + return ImportCardinality.ZeroOrOne; + } + return ImportCardinality.ExactlyOne; + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportCardinalityMismatchException.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportCardinalityMismatchException.cs new file mode 100644 index 00000000000..c3f293ac6d4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportCardinalityMismatchException.cs @@ -0,0 +1,94 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Runtime.Serialization; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// The exception that is thrown when the cardinality of a <see cref="ImportDefinition"/> + /// does not match the cardinality of the <see cref="Export"/> objects available in an + /// <see cref="ExportProvider"/>. + /// </summary> + [Serializable] + [DebuggerTypeProxy(typeof(ImportCardinalityMismatchExceptionDebuggerProxy))] + [DebuggerDisplay("{Message}")] + public class ImportCardinalityMismatchException : Exception + { + /// <summary> + /// Initializes a new instance of the <see cref="ImportCardinalityMismatchException"/> class. + /// </summary> + public ImportCardinalityMismatchException() + : this((string)null, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportCardinalityMismatchException"/> class + /// with the specified error message. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ImportCardinalityMismatchException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + public ImportCardinalityMismatchException(string message) + : this(message, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportCardinalityMismatchException"/> class + /// with the specified error message and exception that is the cause of the + /// exception. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ImportCardinalityMismatchException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + /// <param name="innerException"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="ImportCardinalityMismatchException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.InnerException"/> property to <see langword="null"/>. + /// </param> + public ImportCardinalityMismatchException(string message, Exception innerException) + : base(message, innerException) + { + } + +#if FEATURE_SERIALIZATION + + /// <summary> + /// Initializes a new instance of the <see cref="ImportCardinalityMismatchException"/> class + /// with the specified serialization data. + /// </summary> + /// <param name="info"> + /// The <see cref="SerializationInfo"/> that holds the serialized object data about the + /// <see cref="ImportCardinalityMismatchException"/>. + /// </param> + /// <param name="context"> + /// The <see cref="StreamingContext"/> that contains contextual information about the + /// source or destination. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="info"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="SerializationException"> + /// <paramref name="info"/> is missing a required value. + /// </exception> + /// <exception cref="InvalidCastException"> + /// <paramref name="info"/> contains a value that cannot be cast to the correct type. + /// </exception> + [System.Security.SecuritySafeCritical] + protected ImportCardinalityMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +#endif //FEATURE_SERIALIZATION + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportCardinalityMismatchExceptionDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportCardinalityMismatchExceptionDebuggerProxy.cs new file mode 100644 index 00000000000..d2e92c01707 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportCardinalityMismatchExceptionDebuggerProxy.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Reflection; + +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition +{ + internal class ImportCardinalityMismatchExceptionDebuggerProxy + { + private readonly ImportCardinalityMismatchException _exception; + + public ImportCardinalityMismatchExceptionDebuggerProxy(ImportCardinalityMismatchException exception) + { + Requires.NotNull(exception, "exception"); + + this._exception = exception; + } + + public Exception InnerException + { + get { return _exception.InnerException; } + } + + public string Message + { + get { return _exception.Message; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportManyAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportManyAttribute.cs new file mode 100644 index 00000000000..93a09e1fde1 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportManyAttribute.cs @@ -0,0 +1,168 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that a property, field, or parameter imports a particular set of exports. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes")] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, + AllowMultiple = false, Inherited = false)] + public class ImportManyAttribute : Attribute, IAttributedImport + { + /// <summary> + /// Initializes a new instance of the <see cref="ImportManyAttribute"/> class, importing the + /// set of exports with the default contract name. + /// </summary> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the element\item type of + /// theproperty, field, or parameter type that this is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ImportManyAttribute() + : this((string)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportManyAttribute"/> class, importing the + /// set of exports with the contract name derived from the specified type. + /// </summary> + /// <param name="contractType"> + /// A <see cref="Type"/> of which to derive the contract name of the exports to import, or + /// <see langword="null"/> to use the default contract name. + /// </param> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on + /// <paramref name="contractType"/>. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property, field, + /// or parameter type that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ImportManyAttribute(Type contractType) + : this((string)null, contractType) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportManyAttribute"/> class, importing the + /// set of exports with the specified contract name. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the exports to import, or + /// <see langword="null"/> or an empty string ("") to use the default contract name. + /// </param> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the property, field, + /// or parameter type that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public ImportManyAttribute(string contractName) + : this(contractName, (Type)null) + { + } + + public ImportManyAttribute(string contractName, Type contractType) + { + this.ContractName = contractName; + this.ContractType = contractType; + } + + /// <summary> + /// Gets the contract name of the exports to import. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the contract name of the exports to import. The + /// default value is an empty string (""). + /// </value> + public string ContractName { get; private set; } + + /// <summary> + /// Get the contract type of the export to import. + /// </summary> + /// <value> + /// A <see cref="Type"/> of the export that this import is expecting. The default value is + /// <see langword="null"/> which means that the type will be obtained by looking at the type on + /// the member that this import is attached to. If the type is <see cref="object"/> then the + /// importer is delaring they can accept any exported type. + /// </value> + public Type ContractType { get; private set; } + + /// <summary> + /// Gets or sets a value indicating whether the property or field will be recomposed + /// when exports that provide the same contract that this import expects, have changed + /// in the container. + /// </summary> + /// <value> + /// <see langword="true"/> if the property or field allows for recomposition when exports + /// that provide the same <see cref="ContractName"/> are added or removed from the + /// <see cref="CompositionContainer"/>; otherwise, <see langword="false"/>. + /// The default value is <see langword="false"/>. + /// </value> + public bool AllowRecomposition { get; set; } + + /// <summary> + /// Gets or sets a value indicating that the importer requires a specific + /// <see cref="CreationPolicy"/> for the exports used to satisfy this import. T + /// </summary> + /// <value> + /// <see cref="CreationPolicy.Any"/> - default value, used if the importer doesn't + /// require a specific <see cref="CreationPolicy"/>. + /// + /// <see cref="CreationPolicy.Shared"/> - Requires that all exports used should be shared + /// by everyone in the container. + /// + /// <see cref="CreationPolicy.NonShared"/> - Requires that all exports used should be + /// non-shared in a container and thus everyone gets their own instance. + /// </value> + public CreationPolicy RequiredCreationPolicy { get; set; } + + /// <summary> + /// Gets or sets a value indicating that the importer indicating that the composition engine + /// either should satisfy exports from the local or no local scope. + /// </summary> + /// <value> + /// <see cref="ImportSource.Any"/> - indicates that importer does not + /// require a specific satisfaction scope"/>. + /// + /// <see cref="ImportSource.Local"/> - indicates the importer requires satisfaction to be + /// from the current container. + /// + /// <see cref="ImportSource.NonLocal"/> - indicates the importer requires satisfaction to be + /// from one of the ancestor containers. + /// </value> + public ImportSource Source { get; set; } + + ImportCardinality IAttributedImport.Cardinality + { + get { return ImportCardinality.ZeroOrMore; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportSource.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportSource.cs new file mode 100644 index 00000000000..89797eee8fa --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportSource.cs @@ -0,0 +1,31 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Option placed on an import to determine how composition searches for exports. + /// </summary> + public enum ImportSource : int + { + /// <summary> + /// The import can be satisfied with values from the current or parent (or other ancestor) containers (scopes) + /// </summary> + Any = 0, + + /// <summary> + /// The import can be satisfied with values from the current container (scope) + /// </summary> + Local = 1, + + /// <summary> + /// The import can only be satisfied with values from the parent container (or other ancestor containers) (scopes) + /// </summary> + NonLocal = 2 + + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportingConstructorAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportingConstructorAttribute.cs new file mode 100644 index 00000000000..db4a5ebd098 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ImportingConstructorAttribute.cs @@ -0,0 +1,28 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that a constructor should be used when constructing an attributed part. + /// </summary> + /// <remarks> + /// By default, only a default parameter-less constructor, if available, is used to + /// construct an attributed part. Use this attribute to indicate that a specific constructor + /// should be used. + /// </remarks> + [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes")] + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] + public class ImportingConstructorAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="ImportingConstructorAttribute"/> class. + /// </summary> + public ImportingConstructorAttribute() + { + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/InheritedExportAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/InheritedExportAttribute.cs new file mode 100644 index 00000000000..fb411bc671a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/InheritedExportAttribute.cs @@ -0,0 +1,122 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.Diagnostics.CodeAnalysis; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that a type or interface that provides a particular export. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes")] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)] + public class InheritedExportAttribute : ExportAttribute + { + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type marked with this attribute under the default contract name. + /// </summary> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the type itself, + /// that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public InheritedExportAttribute() + : this((string)null, (Type)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type marked with this attribute under a contract name derived from the specified type. + /// </summary> + /// <param name="contractType"> + /// A <see cref="Type"/> of which to derive the contract name to export the type + /// marked with this attribute, under; or <see langword="null"/> to use the + /// default contract name. + /// </param> + /// <remarks> + /// <para> + /// The contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on + /// <paramref name="contractType"/>. + /// </para> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on the type of the + /// itself, that is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public InheritedExportAttribute(Type contractType) + : this((string)null, contractType) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type or member marked with this attribute under the specified contract name. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name to export the type + /// marked with this attribute, under; or <see langword="null"/> or an empty string + /// ("") to use the default contract name. + /// </param> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on + /// the type itself that this is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public InheritedExportAttribute(string contractName) + : this(contractName, (Type)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportAttribute"/> class, exporting the + /// type or member marked with this attribute under the specified contract name. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name to export the type + /// marked with this attribute, under; or <see langword="null"/> or an empty string + /// ("") to use the default contract name. + /// </param> + /// <param name="contractType"> + /// A <see cref="Type"/> of which to derive the contract name to export the type + /// marked with this attribute, under; or <see langword="null"/> to use the + /// default contract name. + /// </param> + /// <remarks> + /// <para> + /// The default contract name is the result of calling + /// <see cref="AttributedModelServices.GetContractName(Type)"/> on + /// the type itself that this is marked with this attribute. + /// </para> + /// <para> + /// The contract name is compared using a case-sensitive, non-linguistic comparison + /// using <see cref="StringComparer.Ordinal"/>. + /// </para> + /// </remarks> + public InheritedExportAttribute(string contractName, Type contractType) + : base(contractName, contractType) + { + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataAttributeAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataAttributeAttribute.cs new file mode 100644 index 00000000000..81ad7e99c06 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataAttributeAttribute.cs @@ -0,0 +1,23 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that an attribute can be used to provide metadata for a type, property, field, + /// or method marked with the <see cref="ExportAttribute"/>. + /// </summary> + [AttributeUsage(AttributeTargets.Class, + AllowMultiple=false, Inherited=true)] + public sealed class MetadataAttributeAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="MetadataAttributeAttribute"/> class. + /// </summary> + public MetadataAttributeAttribute() + { + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataServices.cs new file mode 100644 index 00000000000..ac57d3bafa3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataServices.cs @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal static class MetadataServices + { + public static readonly IDictionary<string, object> EmptyMetadata = new ReadOnlyDictionary<string, object>(new Dictionary<string, object>(0)); + + public static IDictionary<string, object> AsReadOnly(this IDictionary<string, object> metadata) + { + if (metadata == null) + { + return EmptyMetadata; + } + + if (metadata is ReadOnlyDictionary<string, object>) + { + return metadata; + } + + return new ReadOnlyDictionary<string, object>(metadata); + } + + public static T GetValue<T>(this IDictionary<string, object> metadata, string key) + { + Assumes.NotNull(metadata, "metadata"); + + object untypedValue = true; + if (!metadata.TryGetValue(key, out untypedValue)) + { + return default(T); + } + + if (untypedValue is T) + { + return (T)untypedValue; + } + else + { + return default(T); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs new file mode 100644 index 00000000000..b9f2c41fef0 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs @@ -0,0 +1,381 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; +using System.Reflection.Emit; +using System.Collections; +using System.Security; + +namespace System.ComponentModel.Composition +{ + // // Assume TMetadataView is + // //interface Foo + // //{ + // // public typeRecord1 Record1 { get; } + // // public typeRecord2 Record2 { get; } + // // public typeRecord3 Record3 { get; } + // // public typeRecord4 Record4 { get; } + // //} + // // The class to be generated will look approximately like: + // public class __Foo__MedataViewProxy : TMetadataView + // { + // public __Foo__MedataViewProxy (IDictionary<string, object> metadata) + // { + // if(metadata == null) + // { + // throw InvalidArgumentException("metadata"); + // } + // try + // { + // Record1 = (typeRecord1)Record1; + // Record2 = (typeRecord1)Record2; + // Record3 = (typeRecord1)Record3; + // Record4 = (typeRecord1)Record4; + // } + // catch(InvalidCastException ice) + // { + // //Annotate exception .Data with diagnostic info + // } + // catch(NulLReferenceException ice) + // { + // //Annotate exception .Data with diagnostic info + // } + // } + // // Interface + // public typeRecord1 Record1 { get; } + // public typeRecord2 Record2 { get; } + // public typeRecord3 Record3 { get; } + // public typeRecord4 Record4 { get; } + // } + internal static class MetadataViewGenerator + { + public const string MetadataViewType = "MetadataViewType"; + public const string MetadataItemKey = "MetadataItemKey"; + public const string MetadataItemTargetType = "MetadataItemTargetType"; + public const string MetadataItemSourceType = "MetadataItemSourceType"; + public const string MetadataItemValue = "MetadataItemValue"; + + private static Lock _lock = new Lock(); + private static Dictionary<Type, Type> _proxies = new Dictionary<Type, Type>(); + private static AssemblyName ProxyAssemblyName = new AssemblyName(string.Format(CultureInfo.InvariantCulture, "MetadataViewProxies_{0}", Guid.NewGuid())); +#if FEATURE_CAS_APTCA + private static ModuleBuilder criticalProxyModuleBuilder; +#endif //FEATURE_CAS_APTCA + private static ModuleBuilder transparentProxyModuleBuilder; + + private static Type[] CtorArgumentTypes = new Type[] { typeof(IDictionary<string, object>) }; + private static MethodInfo _mdvDictionaryTryGet = CtorArgumentTypes[0].GetMethod("TryGetValue"); + private static readonly MethodInfo ObjectGetType = typeof(object).GetMethod("GetType", Type.EmptyTypes); +#if FEATURE_CAS_APTCA + private static CustomAttributeBuilder _securityCriticalBuilder = + new CustomAttributeBuilder(typeof(SecurityCriticalAttribute).GetConstructor(Type.EmptyTypes), new object[0]); +#endif //FEATURE_CAS_APTCA + + private static AssemblyBuilder CreateProxyAssemblyBuilder(ConstructorInfo constructorInfo) + { +#if FEATURE_CAS_APTCA + object[] args = new object[0]; + CustomAttributeBuilder accessAttribute = new CustomAttributeBuilder(constructorInfo, args); + CustomAttributeBuilder[] attributes = { accessAttribute }; + return AppDomain.CurrentDomain.DefineDynamicAssembly(ProxyAssemblyName, AssemblyBuilderAccess.Run, attributes, SecurityContextSource.CurrentAppDomain); +#else + return AppDomain.CurrentDomain.DefineDynamicAssembly(ProxyAssemblyName, AssemblyBuilderAccess.Run); +#endif //FEATURE_CAS_APTCA + } + + // Must be called with _lock held + private static ModuleBuilder GetProxyModuleBuilder(bool requiresCritical) + { +#if FEATURE_CAS_APTCA + if(requiresCritical) + { + // Needed a critical modulebuilder so find or make it + if (criticalProxyModuleBuilder == null) + { + var assemblyBuilder = CreateProxyAssemblyBuilder(typeof(AllowPartiallyTrustedCallersAttribute).GetConstructor(Type.EmptyTypes)); + criticalProxyModuleBuilder = assemblyBuilder.DefineDynamicModule("MetadataViewProxiesModule"); + } + return criticalProxyModuleBuilder; + } +#endif //FEATURE_CAS_APTCA + if (transparentProxyModuleBuilder == null) + { + // make a new assemblybuilder and modulebuilder + var assemblyBuilder = CreateProxyAssemblyBuilder(typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes)); + transparentProxyModuleBuilder = assemblyBuilder.DefineDynamicModule("MetadataViewProxiesModule"); + } + + return transparentProxyModuleBuilder; + } + + public static Type GenerateView(Type viewType) + { + Assumes.NotNull(viewType); + Assumes.IsTrue(viewType.IsInterface); + + Type proxyType; + bool foundProxy; + + using (new ReadLock(_lock)) + { + foundProxy = _proxies.TryGetValue(viewType, out proxyType); + } + + // No factory exists + if(!foundProxy) + { + // Try again under a write lock if still none generate the proxy + Type generatedProxyType = GenerateInterfaceViewProxyType(viewType); + Assumes.NotNull(generatedProxyType); + + using (new WriteLock(_lock)) + { + if (!_proxies.TryGetValue(viewType, out proxyType)) + { + proxyType = generatedProxyType; + _proxies.Add(viewType, proxyType); + } + } + } + return proxyType; + } + + private static void GenerateLocalAssignmentFromDefaultAttribute(this ILGenerator IL, DefaultValueAttribute[] attrs, LocalBuilder local) + { + if (attrs.Length > 0) + { + DefaultValueAttribute defaultAttribute = attrs[0]; + IL.LoadValue(defaultAttribute.Value); + if ((defaultAttribute.Value != null) && (defaultAttribute.Value.GetType().IsValueType)) + { + IL.Emit(OpCodes.Box, defaultAttribute.Value.GetType()); + } + IL.Emit(OpCodes.Stloc, local); + } + } + + private static void GenerateFieldAssignmentFromLocalValue(this ILGenerator IL, LocalBuilder local, FieldBuilder field) + { + IL.Emit(OpCodes.Ldarg_0); + IL.Emit(OpCodes.Ldloc, local); + IL.Emit(field.FieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, field.FieldType); + IL.Emit(OpCodes.Stfld, field); + } + + private static void GenerateLocalAssignmentFromFlag(this ILGenerator IL, LocalBuilder local, bool flag) + { + IL.Emit(flag ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + IL.Emit(OpCodes.Stloc, local); + } + + // This must be called with _readerWriterLock held for Write + private static Type GenerateInterfaceViewProxyType(Type viewType) + { + // View type is an interface let's cook an implementation + Type proxyType; + TypeBuilder proxyTypeBuilder; + Type[] interfaces = { viewType }; + bool requiresCritical = false; +#if FEATURE_CAS_APTCA + requiresCritical = !viewType.IsSecurityTransparent; +#endif //FEATURE_CAS_APTCA + + var proxyModuleBuilder = GetProxyModuleBuilder(requiresCritical); + proxyTypeBuilder = proxyModuleBuilder.DefineType( + string.Format(CultureInfo.InvariantCulture, "_proxy_{0}_{1}", viewType.FullName, Guid.NewGuid()), + TypeAttributes.Public, + typeof(object), + interfaces); +#if FEATURE_CAS_APTCA + if (requiresCritical) + { + proxyTypeBuilder.SetCustomAttribute(_securityCriticalBuilder); + } +#endif //FEATURE_CAS_APTCA + // Implement Constructor + ILGenerator proxyCtorIL = proxyTypeBuilder.CreateGeneratorForPublicConstructor(CtorArgumentTypes); + LocalBuilder exception = proxyCtorIL.DeclareLocal(typeof(Exception)); + LocalBuilder exceptionData = proxyCtorIL.DeclareLocal(typeof(IDictionary)); + LocalBuilder sourceType = proxyCtorIL.DeclareLocal(typeof(Type)); + LocalBuilder value = proxyCtorIL.DeclareLocal(typeof(object)); + LocalBuilder usesExportedMD = proxyCtorIL.DeclareLocal(typeof(bool)); + + Label tryConstructView = proxyCtorIL.BeginExceptionBlock(); + + // Implement interface properties + foreach (PropertyInfo propertyInfo in viewType.GetAllProperties()) + { + string fieldName = string.Format(CultureInfo.InvariantCulture, "_{0}_{1}", propertyInfo.Name, Guid.NewGuid()); + + // Cache names and type for exception + string propertyName = string.Format(CultureInfo.InvariantCulture, "{0}", propertyInfo.Name); + + Type[] propertyTypeArguments = new Type[] { propertyInfo.PropertyType }; + Type[] optionalModifiers = null; + Type[] requiredModifiers = null; + +#if FEATURE_ADVANCEDREFLECTION + // PropertyInfo does not support GetOptionalCustomModifiers and GetRequiredCustomModifiers on Silverlight + optionalModifiers = propertyInfo.GetOptionalCustomModifiers(); + requiredModifiers = propertyInfo.GetRequiredCustomModifiers(); + Array.Reverse(optionalModifiers); + Array.Reverse(requiredModifiers); +#endif //FEATURE_ADVANCEDREFLECTION + + // Generate field + FieldBuilder proxyFieldBuilder = proxyTypeBuilder.DefineField( + fieldName, + propertyInfo.PropertyType, + FieldAttributes.Private); + + // Generate property + PropertyBuilder proxyPropertyBuilder = proxyTypeBuilder.DefineProperty( + propertyName, + PropertyAttributes.None, + propertyInfo.PropertyType, + propertyTypeArguments); + + // Generate constructor code for retrieving the metadata value and setting the field + Label tryCastValue = proxyCtorIL.BeginExceptionBlock(); + Label innerTryCastValue; + + DefaultValueAttribute[] attrs = propertyInfo.GetAttributes<DefaultValueAttribute>(false); + if(attrs.Length > 0) + { + innerTryCastValue = proxyCtorIL.BeginExceptionBlock(); + } + + // In constructor set the backing field with the value from the dictionary + Label doneGettingDefaultValue = proxyCtorIL.DefineLabel(); + GenerateLocalAssignmentFromFlag(proxyCtorIL, usesExportedMD, true); + + proxyCtorIL.Emit(OpCodes.Ldarg_1); + proxyCtorIL.Emit(OpCodes.Ldstr, propertyInfo.Name); + proxyCtorIL.Emit(OpCodes.Ldloca, value); + proxyCtorIL.Emit(OpCodes.Callvirt, _mdvDictionaryTryGet); + proxyCtorIL.Emit(OpCodes.Brtrue, doneGettingDefaultValue); + + proxyCtorIL.GenerateLocalAssignmentFromFlag(usesExportedMD, false); + proxyCtorIL.GenerateLocalAssignmentFromDefaultAttribute(attrs, value); + + proxyCtorIL.MarkLabel(doneGettingDefaultValue); + proxyCtorIL.GenerateFieldAssignmentFromLocalValue(value, proxyFieldBuilder); + proxyCtorIL.Emit(OpCodes.Leave, tryCastValue); + + // catch blocks for innerTryCastValue start here + if (attrs.Length > 0) + { + proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException)); + { + Label notUsesExportedMd = proxyCtorIL.DefineLabel(); + proxyCtorIL.Emit(OpCodes.Ldloc, usesExportedMD); + proxyCtorIL.Emit(OpCodes.Brtrue, notUsesExportedMd); + proxyCtorIL.Emit(OpCodes.Rethrow); + proxyCtorIL.MarkLabel(notUsesExportedMd); + proxyCtorIL.GenerateLocalAssignmentFromDefaultAttribute(attrs, value); + proxyCtorIL.GenerateFieldAssignmentFromLocalValue(value, proxyFieldBuilder); + } + proxyCtorIL.EndExceptionBlock(); + } + + // catch blocks for tryCast start here + proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException)); + { + proxyCtorIL.Emit(OpCodes.Stloc, exception); + + proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData); + proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName); + proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType); + proxyCtorIL.Emit(OpCodes.Rethrow); + } + + proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException)); + { + proxyCtorIL.Emit(OpCodes.Stloc, exception); + + proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData); + proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName); + proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType); + proxyCtorIL.Emit(OpCodes.Rethrow); + } + + proxyCtorIL.EndExceptionBlock(); + + if (propertyInfo.CanWrite) + { + // The MetadataView '{0}' is invalid because property '{1}' has a property set method. + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, + Strings.InvalidSetterOnMetadataField, + viewType, + propertyName)); + } + if (propertyInfo.CanRead) + { + // Generate "get" method implementation. + MethodBuilder getMethodBuilder = proxyTypeBuilder.DefineMethod( + string.Format(CultureInfo.InvariantCulture, "get_{0}", propertyName), + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, + CallingConventions.HasThis, + propertyInfo.PropertyType, + requiredModifiers, + optionalModifiers, + Type.EmptyTypes, null, null); + + proxyTypeBuilder.DefineMethodOverride(getMethodBuilder, propertyInfo.GetGetMethod()); +#if FEATURE_CAS_APTCA + if(!viewType.IsSecurityTransparent) + { + getMethodBuilder.SetCustomAttribute(_securityCriticalBuilder); + } +#endif //FEATURE_CAS_APTCA + ILGenerator getMethodIL = getMethodBuilder.GetILGenerator(); + getMethodIL.Emit(OpCodes.Ldarg_0); + getMethodIL.Emit(OpCodes.Ldfld, proxyFieldBuilder); + getMethodIL.Emit(OpCodes.Ret); + + proxyPropertyBuilder.SetGetMethod(getMethodBuilder); + } + } + + proxyCtorIL.Emit(OpCodes.Leave, tryConstructView); + + // catch blocks for constructView start here + proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException)); + { + proxyCtorIL.Emit(OpCodes.Stloc, exception); + + proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData); + proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType); + proxyCtorIL.Emit(OpCodes.Rethrow); + } + proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException)); + { + proxyCtorIL.Emit(OpCodes.Stloc, exception); + + proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData); + proxyCtorIL.Emit(OpCodes.Ldloc, value); + proxyCtorIL.Emit(OpCodes.Call, ObjectGetType); + proxyCtorIL.Emit(OpCodes.Stloc, sourceType); + proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType); + proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemSourceType, sourceType); + proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemValue, value); + proxyCtorIL.Emit(OpCodes.Rethrow); + } + proxyCtorIL.EndExceptionBlock(); + + // Finished implementing interface and constructor + proxyCtorIL.Emit(OpCodes.Ret); + proxyType = proxyTypeBuilder.CreateType(); + + return proxyType; + } + + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewImplementationAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewImplementationAttribute.cs new file mode 100644 index 00000000000..d4834e29914 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewImplementationAttribute.cs @@ -0,0 +1,45 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.Diagnostics.CodeAnalysis; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies that a type, property, field, or method provides a particular export. + /// </summary> + [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] + public sealed class MetadataViewImplementationAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="MetadataViewImplementationAttribute"/> class, declaring the + /// type that holds the implementation for the view. + /// </summary> + /// <param name="typeOfImplementation"> + /// A <see cref="Type"/> for the implementation of the MetadataView. + /// </param> + /// <remarks> + /// <para> + /// By default MetadataViews are generated using reflection emit. This attribute + /// allows the developer to specify the ttype that implements the view rather than + /// using a generated type. + /// </para> + /// </remarks> + public MetadataViewImplementationAttribute(Type implementationType) + { + this.ImplementationType = implementationType; + } + + /// <summary> + /// Get the type that is used to implement the view to which this attribute is attached. + /// </summary> + /// <value> + /// A <see cref="Type"/> of the export that is be provided. The default value is + /// <see langword="null"/> which means that the type will be obtained by looking at the type on + /// the member that this export is attached to. + /// </value> + public Type ImplementationType { get; private set; } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewProvider.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewProvider.cs new file mode 100644 index 00000000000..6c660fcf658 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewProvider.cs @@ -0,0 +1,130 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition +{ + internal static class MetadataViewProvider + { + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public static TMetadataView GetMetadataView<TMetadataView>(IDictionary<string, object> metadata) + { + Assumes.NotNull(metadata); + + Type metadataViewType = typeof(TMetadataView); + + // If the Metadata dictionary is cast compatible with the passed in type + if (metadataViewType.IsAssignableFrom(typeof(IDictionary<string, object>))) + { + return (TMetadataView)metadata; + } + // otherwise is it a metadata view + else + { + Type proxyType; + if (metadataViewType.IsInterface) + { + if(!metadataViewType.IsAttributeDefined<MetadataViewImplementationAttribute>()) + { + try + { + proxyType = MetadataViewGenerator.GenerateView(metadataViewType); + } + catch (TypeLoadException ex) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.NotSupportedInterfaceMetadataView, metadataViewType.FullName), ex); + } + } + else + { + var implementationAttribute = metadataViewType.GetFirstAttribute<MetadataViewImplementationAttribute>(); + proxyType = implementationAttribute.ImplementationType; + if(proxyType == null) + { + throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, + Strings.ContractMismatch_MetadataViewImplementationCanNotBeNull, + metadataViewType.FullName, + proxyType.FullName)); + } + else + { + if(!metadataViewType.IsAssignableFrom(proxyType)) + { + throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, + Strings.ContractMismatch_MetadataViewImplementationDoesNotImplementViewInterface, + metadataViewType.FullName, + proxyType.FullName)); + } + } + } + } + else + { + proxyType = metadataViewType; + } + + // Now we have the type for the proxy create it + try + { + return (TMetadataView)proxyType.SafeCreateInstance(metadata); + } + catch (MissingMethodException ex) + { + // Unable to create an Instance of the Metadata view '{0}' because a constructor could not be selected. Ensure that the type implements a constructor which takes an argument of type IDictionary<string, object>. + throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, + Strings.CompositionException_MetadataViewInvalidConstructor, + proxyType.AssemblyQualifiedName), ex); + } + catch (TargetInvocationException ex) + { + //Unwrap known failures that we want to present as CompositionContractMismatchException + if(metadataViewType.IsInterface) + { + if(ex.InnerException.GetType() == typeof(InvalidCastException)) + { + // Unable to create an Instance of the Metadata view {0} because the exporter exported the metadata for the item {1} with the value {2} as type {3} but the view imports it as type {4}. + throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, + Strings.ContractMismatch_InvalidCastOnMetadataField, + ex.InnerException.Data[MetadataViewGenerator.MetadataViewType], + ex.InnerException.Data[MetadataViewGenerator.MetadataItemKey], + ex.InnerException.Data[MetadataViewGenerator.MetadataItemValue], + ex.InnerException.Data[MetadataViewGenerator.MetadataItemSourceType], + ex.InnerException.Data[MetadataViewGenerator.MetadataItemTargetType]), ex); + } + else if (ex.InnerException.GetType() == typeof(NullReferenceException)) + { + // Unable to create an Instance of the Metadata view {0} because the exporter exported the metadata for the item {1} with a null value and null is not a valid value for type {2}. + throw new CompositionContractMismatchException(string.Format(CultureInfo.CurrentCulture, + Strings.ContractMismatch_NullReferenceOnMetadataField, + ex.InnerException.Data[MetadataViewGenerator.MetadataViewType], + ex.InnerException.Data[MetadataViewGenerator.MetadataItemKey], + ex.InnerException.Data[MetadataViewGenerator.MetadataItemTargetType]), ex); + } + } + throw; + } + } + } + + public static bool IsViewTypeValid(Type metadataViewType) + { + Assumes.NotNull(metadataViewType); + + // If the Metadata dictionary is cast compatible with the passed in type + if (ExportServices.IsDefaultMetadataViewType(metadataViewType) + || metadataViewType.IsInterface + || ExportServices.IsDictionaryConstructorViewType(metadataViewType)) + { + return true; + } + + return false; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartCreationPolicyAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartCreationPolicyAttribute.cs new file mode 100644 index 00000000000..43d0fc9feac --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartCreationPolicyAttribute.cs @@ -0,0 +1,36 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies <see cref="CreationPolicy"/> for a given <see cref="ComposablePart" />. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public sealed class PartCreationPolicyAttribute : Attribute + { + internal static PartCreationPolicyAttribute Default = new PartCreationPolicyAttribute(CreationPolicy.Any); + internal static PartCreationPolicyAttribute Shared = new PartCreationPolicyAttribute(CreationPolicy.Shared); + + /// <summary> + /// Initializes a new instance of the <see cref="PartCreationPolicyAttribute"/> class. + /// </summary> + public PartCreationPolicyAttribute(CreationPolicy creationPolicy) + { + this.CreationPolicy = creationPolicy; + } + + /// <summary> + /// Gets or sets a value indicating the creation policy of the attributed part. + /// </summary> + /// <value> + /// One of the <see cref="CreationPolicy"/> values indicating the creation policy of the + /// attributed part. The default is + /// <see cref="System.ComponentModel.Composition.CreationPolicy.Any"/>. + /// </value> + public CreationPolicy CreationPolicy { get; private set; } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartMetadataAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartMetadataAttribute.cs new file mode 100644 index 00000000000..a75aa4e18d3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartMetadataAttribute.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Specifies metadata for a type to be used as a <see cref="ComposablePartDefinition"/> and + /// <see cref="ComposablePart"/>. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public sealed class PartMetadataAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="PartMetadataAttribute"/> with the + /// specified name and metadata value. + /// </summary> + /// <param name="name"> + /// A <see cref="String"/> containing the name of the metadata value; or + /// <see langword="null"/> to use an empty string (""). + /// </param> + /// <param name="value"> + /// An <see cref="object"/> containing the metadata value. This can be + /// <see langword="null"/>. + /// </param> + public PartMetadataAttribute(string name, object value) + { + this.Name = name ?? string.Empty; + this.Value = value; + } + + /// <summary> + /// Gets the name of the metadata value. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the name of the metadata value. + /// </value> + public string Name + { + get; + private set; + } + + /// <summary> + /// Gets the metadata value. + /// </summary> + /// <value> + /// An <see cref="object"/> containing the metadata value. + /// </value> + public object Value + { + get; + private set; + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartNotDiscoverableAttribute.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartNotDiscoverableAttribute.cs new file mode 100644 index 00000000000..02c82467a6a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/PartNotDiscoverableAttribute.cs @@ -0,0 +1,23 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition +{ + /// <summary> + /// Place on a type that should not be discovered as a <see cref="ComposablePart" /> in + /// a <see cref="ComposablePartCatalog" />. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public sealed class PartNotDiscoverableAttribute : Attribute + { + /// <summary> + /// Initializes a new instance of the <see cref="PartNotDiscoverableAttribute"/> class. + /// </summary> + public PartNotDiscoverableAttribute() + { + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePart.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePart.cs new file mode 100644 index 00000000000..8eea96fc660 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePart.cs @@ -0,0 +1,213 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Defines the <see langword="abstract"/> base class for composable parts, which + /// import and produce exported values. + /// </summary> +#if CONTRACTS_FULL + [ContractClass(typeof(ComposablePartContract))] +#endif + public abstract class ComposablePart + { + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePart"/> class. + /// </summary> + protected ComposablePart() + { + } + + /// <summary> + /// Gets the export definitions that describe the exported values provided by the part. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/> objects describing + /// the exported values provided by the <see cref="ComposablePart"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePart"/> has been disposed of. + /// </exception> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// If the <see cref="ComposablePart"/> was created from a + /// <see cref="ComposablePartDefinition"/>, this property should return the result of + /// <see cref="ComposablePartDefinition.ExportDefinitions"/>. + /// </note> + /// </para> + /// <para> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>. + /// If the <see cref="ComposablePart"/> does not have exports, return an empty + /// <see cref="IEnumerable{T}"/> instead. + /// </note> + /// </para> + /// </remarks> + public abstract IEnumerable<ExportDefinition> ExportDefinitions { get; } + + /// <summary> + /// Gets the import definitions that describe the imports required by the part. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ImportDefinition"/> objects describing + /// the imports required by the <see cref="ComposablePart"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePart"/> has been disposed of. + /// </exception> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// If the <see cref="ComposablePart"/> was created from a + /// <see cref="ComposablePartDefinition"/>, this property should return the result of + /// <see cref="ComposablePartDefinition.ImportDefinitions"/>. + /// </note> + /// </para> + /// <para> + /// <note type="inheritinfo"> + /// Overrides of this property should never return <see langword="null"/>. + /// If the <see cref="ComposablePart"/> does not have imports, return an empty + /// <see cref="IEnumerable{T}"/> instead. + /// </note> + /// </para> + /// </remarks> + public abstract IEnumerable<ImportDefinition> ImportDefinitions { get; } + + /// <summary> + /// Gets the metadata of the part. + /// </summary> + /// <value> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="ComposablePart"/>. The default is an empty, read-only + /// <see cref="IDictionary{TKey, TValue}"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePart"/> has been disposed of. + /// </exception> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// If the <see cref="ComposablePart"/> was created from a + /// <see cref="ComposablePartDefinition"/>, this property should return the result of + /// <see cref="ComposablePartDefinition.Metadata"/>. + /// </note> + /// </para> + /// <para> + /// <note type="inheritinfo"> + /// Overriders of this property should return a read-only + /// <see cref="IDictionary{TKey, TValue}"/> object with a case-sensitive, + /// non-linguistic comparer, such as <see cref="StringComparer.Ordinal"/>, + /// and should never return <see langword="null"/>. If the + /// <see cref="ComposablePart"/> does not contain metadata, return an + /// empty <see cref="IDictionary{TKey, TValue}"/> instead. + /// </note> + /// </para> + /// </remarks> + public virtual IDictionary<string, object> Metadata + { + get + { + return MetadataServices.EmptyMetadata; + } + } + + /// <summary> + /// Called by the composition engine when all required imports on the part have been + /// satisfied. + /// </summary> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePart"/> has been disposed of. + /// </exception> + /// <exception cref="ComposablePartException"> + /// An error occurred activating the <see cref="ComposablePart"/>. + /// </exception> + public virtual void Activate() + { + } + + /// <summary> + /// Gets the exported value described by the specified definition. + /// </summary> + /// <param name="definition"> + /// One of the <see cref="ExportDefinition"/> objects from the + /// <see cref="ExportDefinitions"/> property describing the exported value + /// to return. + /// </param> + /// <returns> + /// The exported value described by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="definition"/> did not originate from the <see cref="ExportDefinitions"/> + /// property on the <see cref="ComposablePart"/>. + /// </exception> + /// <exception cref="InvalidOperationException"> + /// One or more pre-requisite imports, indicated by <see cref="ImportDefinition.IsPrerequisite"/>, + /// have not been set. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePart"/> has been disposed of. + /// </exception> + /// <exception cref="ComposablePartException"> + /// An error occurred getting the exported value described by the <see cref="ExportDefinition"/>. + /// </exception> + public abstract object GetExportedValue(ExportDefinition definition); + + /// <summary> + /// Sets the import described by the specified definition with the specified exports. + /// </summary> + /// <param name="definition"> + /// One of the <see cref="ImportDefinition"/> objects from the + /// <see cref="ImportDefinitions"/> property describing the import to be set. + /// </param> + /// <param name="exports"> + /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects of which + /// to set the import described by <paramref name="definition"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exports"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="definition"/> did not originate from the <see cref="ImportDefinitions"/> + /// property on the <see cref="ComposablePart"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exports"/> contains an element that is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exports"/> is empty and <see cref="ImportDefinition.Cardinality"/> is + /// <see cref="ImportCardinality.ExactlyOne"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exports"/> contains more than one element and + /// <see cref="ImportDefinition.Cardinality"/> is <see cref="ImportCardinality.ZeroOrOne"/> or + /// <see cref="ImportCardinality.ExactlyOne"/>. + /// </exception> + /// <exception cref="InvalidOperationException"> + /// <see cref="Activate"/> has been previously called and + /// <see cref="ImportDefinition.IsRecomposable"/> is <see langword="false"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePart"/> has been disposed of. + /// </exception> + /// <exception cref="ComposablePartException"> + /// An error occurred setting the import described by the <see cref="ImportDefinition"/>. + /// </exception> + public abstract void SetImport(ImportDefinition definition, IEnumerable<Export> exports); + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartCatalog.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartCatalog.cs new file mode 100644 index 00000000000..d296543a9fb --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartCatalog.cs @@ -0,0 +1,188 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.ComponentModel.Composition.Hosting; + + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Defines the <see langword="abstract"/> base class for composable part catalogs, which produce + /// and return <see cref="ComposablePartDefinition"/> objects. + /// </summary> + /// <remarks> + /// This type is thread safe. + /// </remarks> + [DebuggerTypeProxy(typeof(ComposablePartCatalogDebuggerProxy))] + public abstract class ComposablePartCatalog : IEnumerable<ComposablePartDefinition>, IDisposable + { + private bool _isDisposed; + private volatile IQueryable<ComposablePartDefinition> _queryableParts = null; + + private static readonly List<Tuple<ComposablePartDefinition, ExportDefinition>> _EmptyExportsList = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartCatalog"/> class. + /// </summary> + protected ComposablePartCatalog() + { + } + + /// <summary> + /// Gets the part definitions of the catalog. + /// </summary> + /// <value> + /// A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the + /// <see cref="ComposablePartCatalog"/>. + /// </value> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePartCatalog"/> has been disposed of. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>. + /// </note> + /// </remarks> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)] + public virtual IQueryable<ComposablePartDefinition> Parts + { + get + { + this.ThrowIfDisposed(); + if(this._queryableParts == null) + { + // Guarantee one time only set _queryableParts + var p = this.AsQueryable(); + // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. +#pragma warning disable 420 + Interlocked.CompareExchange(ref this._queryableParts, p, null); +#pragma warning restore 420 + Assumes.NotNull(this._queryableParts); + } + return this._queryableParts; + } + } + + /// <summary> + /// Returns the export definitions that match the constraint defined by the specified definition. + /// </summary> + /// <param name="definition"> + /// The <see cref="ImportDefinition"/> that defines the conditions of the + /// <see cref="ExportDefinition"/> objects to return. + /// </param> + /// <returns> + /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the + /// <see cref="ExportDefinition"/> objects and their associated + /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined + /// by <paramref name="definition"/>. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ObjectDisposedException"> + /// The <see cref="ComposablePartCatalog"/> has been disposed of. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>, if no + /// <see cref="ExportDefinition"/> match the conditions defined by + /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>. + /// </note> + /// </remarks> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public virtual IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + this.ThrowIfDisposed(); + + Requires.NotNull(definition, "definition"); + Contract.Ensures(Contract.Result<IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>>>() != null); + + List<Tuple<ComposablePartDefinition, ExportDefinition>> exports = null; + var candidateParts = this.GetCandidateParts(definition); + if (candidateParts != null) + { + foreach (var part in candidateParts) + { + var partExports = part.GetExports(definition); + if (partExports != ComposablePartDefinition._EmptyExports) + { + exports = exports.FastAppendToListAllowNulls(partExports); + } + } + } + + return exports ?? _EmptyExportsList; + } + + + internal virtual IEnumerable<ComposablePartDefinition> GetCandidateParts(ImportDefinition definition) + { + return this; + } + + + /// <summary> + /// Releases the unmanaged resources used by the <see cref="ComposablePartCatalog"/> and + /// optionally releases the managed resources. + /// </summary> + /// <param name="disposing"> + /// <see langword="true"/> to release both managed and unmanaged resources; + /// <see langword="false"/> to release only unmanaged resources. + /// </param> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + this._isDisposed = true; + } + + [DebuggerStepThrough] + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053", Justification = "Suppressing warning because this validator has no public contract")] + private void ThrowIfDisposed() + { + if (this._isDisposed) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + // + // If neither Parts nor GetEnumerator() is overriden then return an empty list + // If GetEnumerator is overridden this code should not be invoked: ReferenceAssemblies mark it as Abstract or Not present + // We verify whether Parts is overriden by seeing if the object returns matched the one cached for this instance + // Note: a query object is only cached if Parts is invoked on a catalog which did not implement it + // Because reference assemblies do not expose Parts and we no longer use it, it should not get invoked by 3rd parties + // Because the reference assemblies mark GetEnumerator as Abstract 3rd party code should not lack an implementation + // That implementation should not try to call this implementation + // Our code doies delegate to Parts in the DebuggerProxies of course. + // + public virtual IEnumerator<ComposablePartDefinition> GetEnumerator() + { + var parts = this.Parts; + if(object.ReferenceEquals(parts, this._queryableParts)) + { + return Enumerable.Empty<ComposablePartDefinition>().GetEnumerator(); + } + return parts.GetEnumerator(); + } + + Collections.IEnumerator Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartCatalogDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartCatalogDebuggerProxy.cs new file mode 100644 index 00000000000..15f0031dc00 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartCatalogDebuggerProxy.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.ObjectModel; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Primitives +{ + // This proxy is needed to pretty up ComposablePartCatalog.Parts; IQueryable<T> + // instances are not displayed in a very friendly way in the debugger. + internal class ComposablePartCatalogDebuggerProxy + { + private readonly ComposablePartCatalog _catalog; + + public ComposablePartCatalogDebuggerProxy(ComposablePartCatalog catalog) + { + Requires.NotNull(catalog, "catalog"); + + this._catalog = catalog; + } + + public ReadOnlyCollection<ComposablePartDefinition> Parts + { + // NOTE: This shouldn't be cached, so that on every query of + // the current value of the underlying catalog is respected. + // We use ReadOnlyCollection as arrays do not have the + // appropriate debugger display attributes applied to them. + get { return this._catalog.Parts.ToReadOnlyCollection(); } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartDefinition.cs new file mode 100644 index 00000000000..013a3d101d6 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartDefinition.cs @@ -0,0 +1,131 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Defines the <see langword="abstract"/> base class for composable part definitions, which + /// describe, and allow the creation of, <see cref="ComposablePart"/> objects. + /// </summary> +#if CONTRACTS_FULL + [ContractClass(typeof(ComposablePartDefinitionContract))] +#endif + public abstract class ComposablePartDefinition + { + static internal readonly IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> _EmptyExports = Enumerable.Empty<Tuple<ComposablePartDefinition, ExportDefinition>>(); + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartDefinition"/> class. + /// </summary> + protected ComposablePartDefinition() + { + } + + /// <summary> + /// Gets the export definitions that describe the exported values provided by parts + /// created by the definition. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ExportDefinition"/> objects describing + /// the exported values provided by <see cref="ComposablePart"/> objects created by the + /// <see cref="ComposablePartDefinition"/>. + /// </value> + /// <remarks> + /// <note type="inheritinfo"> + /// Overrides of this property should never return <see langword="null"/>. + /// If the <see cref="ComposablePart"/> objects created by the + /// <see cref="ComposablePartDefinition"/> do not provide exported values, return + /// an empty <see cref="IEnumerable{T}"/> instead. + /// </note> + /// </remarks> + public abstract IEnumerable<ExportDefinition> ExportDefinitions { get; } + + /// <summary> + /// Gets the import definitions that describe the imports required by parts created + /// by the definition. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of <see cref="ImportDefinition"/> objects describing + /// the imports required by <see cref="ComposablePart"/> objects created by the + /// <see cref="ComposablePartDefinition"/>. + /// </value> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>. + /// If the <see cref="ComposablePart"/> objects created by the + /// <see cref="ComposablePartDefinition"/> do not have imports, return an empty + /// <see cref="IEnumerable{T}"/> instead. + /// </note> + /// </remarks> + public abstract IEnumerable<ImportDefinition> ImportDefinitions { get; } + + /// <summary> + /// Gets the metadata of the definition. + /// </summary> + /// <value> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="ComposablePartDefinition"/>. The default is an empty, read-only + /// <see cref="IDictionary{TKey, TValue}"/>. + /// </value> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// Overriders of this property should return a read-only + /// <see cref="IDictionary{TKey, TValue}"/> object with a case-sensitive, + /// non-linguistic comparer, such as <see cref="StringComparer.Ordinal"/>, + /// and should never return <see langword="null"/>. If the + /// <see cref="ComposablePartDefinition"/> does contain metadata, + /// return an empty <see cref="IDictionary{TKey, TValue}"/> instead. + /// </note> + /// </para> + /// </remarks> + public virtual IDictionary<string, object> Metadata + { + get { return MetadataServices.EmptyMetadata; } + } + + /// <summary> + /// Creates a new instance of a part that the definition describes. + /// </summary> + /// <returns> + /// The created <see cref="ComposablePart"/>. + /// </returns> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// Derived types overriding this method should return a new instance of a + /// <see cref="ComposablePart"/> on every invoke and should never return + /// <see langword="null"/>. + /// </note> + /// </para> + /// </remarks> + public abstract ComposablePart CreatePart(); + + internal virtual IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + List<Tuple<ComposablePartDefinition, ExportDefinition>> exports = null; + foreach (var export in this.ExportDefinitions) + { + if (definition.IsConstraintSatisfiedBy(export)) + { + if (exports == null) + { + exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>(); + } + exports.Add(new Tuple<ComposablePartDefinition, ExportDefinition>(this, export)); + } + } + + return exports ?? _EmptyExports; + } + + internal virtual ComposablePartDefinition GetGenericPartDefinition() + { + return null; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartException.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartException.cs new file mode 100644 index 00000000000..dcac158b059 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartException.cs @@ -0,0 +1,181 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using System.Security.Permissions; +using Microsoft.Internal; +using Microsoft.Internal.Runtime.Serialization; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// The exception that is thrown when an error occurs when calling methods on a + /// <see cref="ComposablePart"/>. + /// </summary> + [Serializable] + [DebuggerTypeProxy(typeof(ComposablePartExceptionDebuggerProxy))] + [DebuggerDisplay("{Message}")] + public class ComposablePartException : Exception + { + private readonly ICompositionElement _element; + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartException"/> class. + /// </summary> + public ComposablePartException() + : this((string)null, (ICompositionElement)null, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartException"/> class + /// with the specified error message. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + /// <param name="element"> + /// The <see cref="ICompositionElement"/> that is the cause of the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="ComposablePartException.Element"/> property to + /// <see langword="null"/>. + /// </param> + public ComposablePartException(string message) + : this(message, (ICompositionElement)null, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartException"/> class + /// with the specified error message and composition element that is the cause of + /// the exception. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + public ComposablePartException(string message, ICompositionElement element) + : this(message, element, (Exception)null) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartException"/> class + /// with the specified error message and exception that is the cause of the + /// exception. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + /// <param name="innerException"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.InnerException"/> property to <see langword="null"/>. + /// </param> + public ComposablePartException(string message, Exception innerException) + : this(message, (ICompositionElement)null, innerException) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartException"/> class + /// with the specified error message, and composition element and exception that + /// are the cause of the exception. + /// </summary> + /// <param name="message"> + /// A <see cref="String"/> containing a message that describes the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.Message"/> property to its default value. + /// </param> + /// <param name="element"> + /// The <see cref="ICompositionElement"/> that is the cause of the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="ComposablePartException.Element"/> property to + /// <see langword="null"/>. + /// </param> + /// <param name="innerException"> + /// The <see cref="Exception"/> that is the underlying cause of the + /// <see cref="ComposablePartException"/>; or <see langword="null"/> to set + /// the <see cref="Exception.InnerException"/> property to <see langword="null"/>. + /// </param> + public ComposablePartException(string message, ICompositionElement element, Exception innerException) + : base(message, innerException) + { + _element = element; + } + +#if FEATURE_SERIALIZATION + /// <summary> + /// Initializes a new instance of the <see cref="ComposablePartException"/> class + /// with the specified serialization data. + /// </summary> + /// <param name="info"> + /// The <see cref="SerializationInfo"/> that holds the serialized object data about the + /// <see cref="ComposablePartException"/>. + /// </param> + /// <param name="context"> + /// The <see cref="StreamingContext"/> that contains contextual information about the + /// source or destination. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="info"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="SerializationException"> + /// <paramref name="info"/> is missing a required value. + /// </exception> + /// <exception cref="InvalidCastException"> + /// <paramref name="info"/> contains a value that cannot be cast to the correct type. + /// </exception> + [System.Security.SecuritySafeCritical] + protected ComposablePartException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _element = info.GetValue<ICompositionElement>("Element"); + } + +#endif //FEATURE_SERIALIZATION + + /// <summary> + /// Gets the composition element that is the cause of the exception. + /// </summary> + /// <value> + /// The <see cref="ICompositionElement"/> that is the cause of the + /// <see cref="ComposablePartException"/>. The default is <see langword="null"/>. + /// </value> + public ICompositionElement Element + { + get { return _element; } + } + +#if FEATURE_SERIALIZATION + /// <summary> + /// Gets the serialization data of the exception. + /// </summary> + /// <param name="info"> + /// The <see cref="SerializationInfo"/> that holds the serialized object data about the + /// <see cref="ComposablePartException"/>. + /// </param> + /// <param name="context"> + /// The <see cref="StreamingContext"/> that contains contextual information about the + /// source or destination. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="info"/> is <see langword="null"/>. + /// </exception> + [System.Security.SecurityCritical] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + + info.AddValue("Element", _element.ToSerializableElement()); + } +#endif //FEATURE_SERIALIZATION + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartExceptionDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartExceptionDebuggerProxy.cs new file mode 100644 index 00000000000..6e4d0366fc3 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ComposablePartExceptionDebuggerProxy.cs @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics; +using System.Reflection; + +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.Primitives +{ + internal class ComposablePartExceptionDebuggerProxy + { + private readonly ComposablePartException _exception; + + public ComposablePartExceptionDebuggerProxy(ComposablePartException exception) + { + Requires.NotNull(exception, "exception"); + + this._exception = exception; + } + + public ICompositionElement Element + { + get { return _exception.Element; } + } + + public Exception InnerException + { + get { return _exception.InnerException; } + } + + public string Message + { + get { return _exception.Message; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElement.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElement.cs new file mode 100644 index 00000000000..23f7677f571 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElement.cs @@ -0,0 +1,30 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Primitives +{ + // Represents the ICompositionElement placeholder for an + // object that does not implement ICompositionElement + [DebuggerTypeProxy(typeof(CompositionElementDebuggerProxy))] + [Serializable] + internal class CompositionElement : SerializableCompositionElement + { + private static readonly ICompositionElement UnknownOrigin = new SerializableCompositionElement(Strings.CompositionElement_UnknownOrigin, (ICompositionElement)null); + private readonly object _underlyingObject; + + public CompositionElement(object underlyingObject) + : base(underlyingObject.ToString(), UnknownOrigin) + { + this._underlyingObject = underlyingObject; + } + + public object UnderlyingObject + { + get { return _underlyingObject; } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElementDebuggerProxy.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElementDebuggerProxy.cs new file mode 100644 index 00000000000..00442c50646 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElementDebuggerProxy.cs @@ -0,0 +1,39 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Primitives +{ + // Because the debugger displays only the members available on ICompositionElement + // when viewing CompositionError.Element in the watch and data tips windows, we + // need this proxy so that the underlying object wrapped by the CompositionElement + // placeholder is displayed by default. + internal class CompositionElementDebuggerProxy + { + private readonly CompositionElement _element; + + public CompositionElementDebuggerProxy(CompositionElement element) + { + Requires.NotNull(element, "element"); + + this._element = element; + } + + public string DisplayName + { + get { return this._element.DisplayName; } + } + + public ICompositionElement Origin + { + get { return this._element.Origin; } + } + + public object UnderlyingObject + { + get { return this._element.UnderlyingObject; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElementExtensions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElementExtensions.cs new file mode 100644 index 00000000000..47e8cfb888d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/CompositionElementExtensions.cs @@ -0,0 +1,82 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Primitives +{ + internal static class CompositionElementExtensions + { +#if FEATURE_SERIALIZATION + public static ICompositionElement ToSerializableElement(this ICompositionElement element) + { + return SerializableCompositionElement.FromICompositionElement(element); + } +#endif //FEATURE_SERIALIZATION + public static ICompositionElement ToElement(this Export export) + { + // First try the export + ICompositionElement element = export as ICompositionElement; + if (element != null) + { + return element; + } + + // Otherwise, try the definition + return ToElement(export.Definition); + } + + public static ICompositionElement ToElement(this ExportDefinition definition) + { + return ToElementCore(definition); + } + + public static ICompositionElement ToElement(this ImportDefinition definition) + { + return ToElementCore(definition); + } + + public static ICompositionElement ToElement(this ComposablePart part) + { + return ToElementCore(part); + } + + public static ICompositionElement ToElement(this ComposablePartDefinition definition) + { + return ToElementCore(definition); + } + + public static string GetDisplayName(this ComposablePartDefinition definition) + { + return GetDisplayNameCore(definition); + } + + public static string GetDisplayName(this ComposablePartCatalog catalog) + { + return GetDisplayNameCore(catalog); + } + + private static string GetDisplayNameCore(object value) + { + ICompositionElement element = value as ICompositionElement; + if (element != null) + { + return element.DisplayName; + } + + return value.ToString(); + } + + private static ICompositionElement ToElementCore(object value) + { + ICompositionElement element = value as ICompositionElement; + if (element != null) + { + return element; + } + + return new CompositionElement(value); + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ContractBasedImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ContractBasedImportDefinition.cs new file mode 100644 index 00000000000..a221e686a43 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ContractBasedImportDefinition.cs @@ -0,0 +1,397 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Represents a contract name and metadata-based import + /// required by a <see cref="ComposablePart"/> object. + /// </summary> + public class ContractBasedImportDefinition : ImportDefinition + { + // Unlike contract name, both metadata and required metadata has a sensible default; set it to an empty + // enumerable, so that derived definitions only need to override ContractName by default. + private readonly IEnumerable<KeyValuePair<string, Type>> _requiredMetadata = Enumerable.Empty<KeyValuePair<string, Type>>(); + private Expression<Func<ExportDefinition, bool>> _constraint; + private readonly CreationPolicy _requiredCreationPolicy = CreationPolicy.Any; + private readonly string _requiredTypeIdentity = null; + private bool _isRequiredMetadataValidated = false; + + /// <summary> + /// Initializes a new instance of the <see cref="ContractBasedImportDefinition"/> class. + /// </summary> + /// <remarks> + /// <note type="inheritinfo"> + /// Derived types calling this constructor can optionally override the + /// <see cref="ImportDefinition.ContractName"/>, <see cref="RequiredTypeIdentity"/>, + /// <see cref="RequiredMetadata"/>, <see cref="ImportDefinition.Cardinality"/>, + /// <see cref="ImportDefinition.IsPrerequisite"/>, <see cref="ImportDefinition.IsRecomposable"/> + /// and <see cref="RequiredCreationPolicy"/> properties. + /// </note> + /// </remarks> + protected ContractBasedImportDefinition() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ContractBasedImportDefinition"/> class + /// with the specified contract name, required metadataq, cardinality, value indicating + /// if the import definition is recomposable and a value indicating if the import definition + /// is a prerequisite. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Export"/> required by the <see cref="ContractBasedImportDefinition"/>. + /// </param> + /// <param name="requiredTypeIdentity"> + /// The type identity of the export type expected. Use <see cref="AttributedModelServices.GetTypeIdentity(Type)"/> + /// to generate a type identity for a given type. If no specific type is required pass <see langword="null"/>. + /// </param> + /// <param name="requiredMetadata"> + /// An <see cref="IEnumerable{T}"/> of <see cref="String"/> objects containing + /// the metadata names of the <see cref="Export"/> required by the + /// <see cref="ContractBasedImportDefinition"/>; or <see langword="null"/> to + /// set the <see cref="RequiredMetadata"/> property to an empty <see cref="IEnumerable{T}"/>. + /// </param> + /// <param name="cardinality"> + /// One of the <see cref="ImportCardinality"/> values indicating the + /// cardinality of the <see cref="Export"/> objects required by the + /// <see cref="ContractBasedImportDefinition"/>. + /// </param> + /// <param name="isRecomposable"> + /// <see langword="true"/> if the <see cref="ContractBasedImportDefinition"/> can be satisfied + /// multiple times throughout the lifetime of a <see cref="ComposablePart"/>, otherwise, + /// <see langword="false"/>. + /// </param> + /// <param name="isPrerequisite"> + /// <see langword="true"/> if the <see cref="ContractBasedImportDefinition"/> is required to be + /// satisfied before a <see cref="ComposablePart"/> can start producing exported + /// objects; otherwise, <see langword="false"/>. + /// </param> + /// <param name="requiredCreationPolicy"> + /// A value indicating that the importer requires a specific <see cref="CreationPolicy"/> for + /// the exports used to satisfy this import. If no specific <see cref="CreationPolicy"/> is needed + /// pass the default <see cref="CreationPolicy.Any"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="contractName"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="contractName"/> is an empty string (""). + /// <para> + /// -or- + /// </para> + /// <paramref name="requiredMetadata"/> contains an element that is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="cardinality"/> is not one of the <see cref="ImportCardinality"/> + /// values. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public ContractBasedImportDefinition(string contractName, string requiredTypeIdentity, IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, bool isRecomposable, bool isPrerequisite, CreationPolicy requiredCreationPolicy) + : this(contractName, requiredTypeIdentity, requiredMetadata, cardinality, isRecomposable, isPrerequisite, requiredCreationPolicy, MetadataServices.EmptyMetadata) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ContractBasedImportDefinition"/> class + /// with the specified contract name, required metadataq, cardinality, value indicating + /// if the import definition is recomposable and a value indicating if the import definition + /// is a prerequisite. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Export"/> required by the <see cref="ContractBasedImportDefinition"/>. + /// </param> + /// <param name="requiredTypeIdentity"> + /// The type identity of the export type expected. Use <see cref="AttributedModelServices.GetTypeIdentity(Type)"/> + /// to generate a type identity for a given type. If no specific type is required pass <see langword="null"/>. + /// </param> + /// <param name="requiredMetadata"> + /// An <see cref="IEnumerable{T}"/> of <see cref="String"/> objects containing + /// the metadata names of the <see cref="Export"/> required by the + /// <see cref="ContractBasedImportDefinition"/>; or <see langword="null"/> to + /// set the <see cref="RequiredMetadata"/> property to an empty <see cref="IEnumerable{T}"/>. + /// </param> + /// <param name="cardinality"> + /// One of the <see cref="ImportCardinality"/> values indicating the + /// cardinality of the <see cref="Export"/> objects required by the + /// <see cref="ContractBasedImportDefinition"/>. + /// </param> + /// <param name="isRecomposable"> + /// <see langword="true"/> if the <see cref="ContractBasedImportDefinition"/> can be satisfied + /// multiple times throughout the lifetime of a <see cref="ComposablePart"/>, otherwise, + /// <see langword="false"/>. + /// </param> + /// <param name="isPrerequisite"> + /// <see langword="true"/> if the <see cref="ContractBasedImportDefinition"/> is required to be + /// satisfied before a <see cref="ComposablePart"/> can start producing exported + /// objects; otherwise, <see langword="false"/>. + /// </param> + /// <param name="requiredCreationPolicy"> + /// A value indicating that the importer requires a specific <see cref="CreationPolicy"/> for + /// the exports used to satisfy this import. If no specific <see cref="CreationPolicy"/> is needed + /// pass the default <see cref="CreationPolicy.Any"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="contractName"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="contractName"/> is an empty string (""). + /// <para> + /// -or- + /// </para> + /// <paramref name="requiredMetadata"/> contains an element that is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="cardinality"/> is not one of the <see cref="ImportCardinality"/> + /// values. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public ContractBasedImportDefinition(string contractName, string requiredTypeIdentity, IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, bool isRecomposable, bool isPrerequisite, CreationPolicy requiredCreationPolicy, IDictionary<string, object> metadata) + : base(contractName, cardinality, isRecomposable, isPrerequisite, metadata) + { + Requires.NotNullOrEmpty(contractName, "contractName"); + + this._requiredTypeIdentity = requiredTypeIdentity; + + if (requiredMetadata != null) + { + this._requiredMetadata = requiredMetadata; + } + + this._requiredCreationPolicy = requiredCreationPolicy; + } + + /// <summary> + /// The type identity of the export type expected. + /// </summary> + /// <value> + /// A <see cref="string"/> that is generated by <see cref="AttributedModelServices.GetTypeIdentity(Type)"/> + /// on the type that this import expects. If the value is <see langword="null"/> then this import + /// doesn't expect a particular type. + /// </value> + public virtual string RequiredTypeIdentity + { + get { return this._requiredTypeIdentity; } + } + + /// <summary> + /// Gets the metadata names of the export required by the import definition. + /// </summary> + /// <value> + /// An <see cref="IEnumerable{T}"/> of pairs of metadata keys and types of the <see cref="Export"/> required by the + /// <see cref="ContractBasedImportDefinition"/>. The default is an empty + /// <see cref="IEnumerable{T}"/>. + /// </value> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/> + /// or return an <see cref="IEnumerable{T}"/> that contains an element that is + /// <see langword="null"/>. If the definition does not contain required metadata, + /// return an empty <see cref="IEnumerable{T}"/> instead. + /// </note> + /// </remarks> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public virtual IEnumerable<KeyValuePair<string, Type>> RequiredMetadata + { + get + { + Contract.Ensures(Contract.Result<IEnumerable<KeyValuePair<string, Type>>>() != null); + + // NOTE : unlike other arguments, we validate this one as late as possible, because its validation may lead to type loading + this.ValidateRequiredMetadata(); + + return this._requiredMetadata; + } + } + + private void ValidateRequiredMetadata() + { + if (!this._isRequiredMetadataValidated) + { + foreach (KeyValuePair<string, Type> metadataItem in this._requiredMetadata) + { + if ((metadataItem.Key == null) || (metadataItem.Value == null)) + { + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, Strings.Argument_NullElement, "requiredMetadata")); + } + } + this._isRequiredMetadataValidated = true; + } + } + + /// <summary> + /// Gets or sets a value indicating that the importer requires a specific + /// <see cref="CreationPolicy"/> for the exports used to satisfy this import. T + /// </summary> + /// <value> + /// <see cref="CreationPolicy.Any"/> - default value, used if the importer doesn't + /// require a specific <see cref="CreationPolicy"/>. + /// + /// <see cref="CreationPolicy.Shared"/> - Requires that all exports used should be shared + /// by everyone in the container. + /// + /// <see cref="CreationPolicy.NonShared"/> - Requires that all exports used should be + /// non-shared in a container and thus everyone gets their own instance. + /// </value> + public virtual CreationPolicy RequiredCreationPolicy + { + get { return this._requiredCreationPolicy; } + } + + /// <summary> + /// Gets an expression that defines conditions that must be matched for the import + /// described by the import definition to be satisfied. + /// </summary> + /// <returns> + /// A <see cref="Expression{TDelegate}"/> containing a <see cref="Func{T, TResult}"/> + /// that defines the conditions that must be matched for the + /// <see cref="ImportDefinition"/> to be satisfied by an <see cref="Export"/>. + /// </returns> + /// <remarks> + /// <para> + /// This property returns an expression that defines conditions based on the + /// <see cref="ImportDefinition.ContractName"/>, <see cref="RequiredTypeIdentity"/>, + /// <see cref="RequiredMetadata"/>, and <see cref="RequiredCreationPolicy"/> + /// properties. + /// </para> + /// </remarks> + public override Expression<Func<ExportDefinition, bool>> Constraint + { + get + { + if (this._constraint == null) + { + this._constraint = ConstraintServices.CreateConstraint(this.ContractName, this.RequiredTypeIdentity, this.RequiredMetadata, this.RequiredCreationPolicy); + } + + return this._constraint; + } + } + + /// <summary> + /// Executes an optimized version of the contraint given by the <see cref="Constraint"/> property + /// </summary> + /// <param name="exportDefinition"> + /// A definition for a <see cref="Export"/> used to determine if it satisfies the + /// requirements for this <see cref="ImportDefinition"/>. + /// </param> + /// <returns> + /// <see langword="True"/> if the <see cref="Export"/> satisfies the requirements for + /// this <see cref="ImportDefinition"/>, otherwise returns <see langword="False"/>. + /// </returns> + /// <remarks> + /// <note type="inheritinfo"> + /// Overrides of this method can provide a more optimized execution of the + /// <see cref="Constraint"/> property but the result should remain consistent. + /// </note> + /// </remarks> + /// <exception cref="ArgumentNullException"> + /// <paramref name="exportDefinition"/> is <see langword="null"/>. + /// </exception> + public override bool IsConstraintSatisfiedBy(ExportDefinition exportDefinition) + { + Requires.NotNull(exportDefinition, "exportDefinition"); + + if (!StringComparers.ContractName.Equals(this.ContractName, exportDefinition.ContractName)) + { + return false; + } + + return MatchRequiredMatadata(exportDefinition); + } + + private bool MatchRequiredMatadata(ExportDefinition definition) + { + if (!string.IsNullOrEmpty(this.RequiredTypeIdentity)) + { + string exportTypeIdentity = definition.Metadata.GetValue<string>(CompositionConstants.ExportTypeIdentityMetadataName); + + if (!StringComparers.ContractName.Equals(this.RequiredTypeIdentity, exportTypeIdentity)) + { + return false; + } + } + + foreach (KeyValuePair<string, Type> metadataItem in this.RequiredMetadata) + { + string metadataKey = metadataItem.Key; + Type metadataValueType = metadataItem.Value; + + object metadataValue = null; + if (!definition.Metadata.TryGetValue(metadataKey, out metadataValue)) + { + return false; + } + + if (metadataValue != null) + { + // the metadata value is not null, we can rely on IsInstanceOfType to do the right thing + if (!metadataValueType.IsInstanceOfType(metadataValue)) + { + return false; + } + } + else + { + // this is an unfortunate special case - typeof(object).IsInstanceofType(null) == false + // basically nulls are not considered valid values for anything + // We want them to match anything that is a reference type + if (metadataValueType.IsValueType) + { + // this is a pretty expensive check, but we only invoke it when metadata values are null, which is very rare + return false; + } + } + } + + if (this.RequiredCreationPolicy == CreationPolicy.Any) + { + return true; + } + + CreationPolicy exportPolicy = definition.Metadata.GetValue<CreationPolicy>(CompositionConstants.PartCreationPolicyMetadataName); + return exportPolicy == CreationPolicy.Any || + exportPolicy == this.RequiredCreationPolicy; + } + + public override string ToString() + { + var sb = new StringBuilder(); + + sb.Append(string.Format("\n\tContractName\t{0}", this.ContractName)); + sb.Append(string.Format("\n\tRequiredTypeIdentity\t{0}", this.RequiredTypeIdentity)); + if(this._requiredCreationPolicy != CreationPolicy.Any) + { + sb.Append(string.Format("\n\tRequiredCreationPolicy\t{0}", this.RequiredCreationPolicy)); + } + + if(this._requiredMetadata.Count() > 0) + { + sb.Append(string.Format("\n\tRequiredMetadata")); + foreach (KeyValuePair<string, Type> metadataItem in this._requiredMetadata) + { + sb.Append(string.Format("\n\t\t{0}\t({1})", metadataItem.Key, metadataItem.Value)); + } + } + return sb.ToString(); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/Export.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/Export.cs new file mode 100644 index 00000000000..fdcdfe6f358 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/Export.cs @@ -0,0 +1,253 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Internal; +using System.Threading; +using System.Diagnostics.Contracts; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Represents an export. That is, a type that is made up of a delay-created exported value + /// and metadata that describes that object. + /// </summary> + public class Export + { + private readonly ExportDefinition _definition; + private readonly Func<object> _exportedValueGetter; + private static readonly object _EmptyValue = new object(); + private volatile object _exportedValue = Export._EmptyValue; + + /// <summary> + /// Initializes a new instance of the <see cref="Export"/> class. + /// </summary> + /// <remarks> + /// <note type="inheritinfo"> + /// Derived types calling this constructor must override <see cref="Definition"/> + /// and <see cref="GetExportedValueCore"/>. + /// </note> + /// </remarks> + protected Export() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="Export"/> class + /// with the specified contract name and exported value getter. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Export"/>. + /// </param> + /// <param name="exportedValueGetter"> + /// A <see cref="Func{T}"/> that is called to create the exported value of the + /// <see cref="Export"/>. This allows the creation of the object to be delayed + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="contractName"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exportedValueGetter"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="contractName"/> is an empty string (""). + /// </exception> + public Export(string contractName, Func<object> exportedValueGetter) + : this(new ExportDefinition(contractName, (IDictionary<string, object>)null), exportedValueGetter) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="Export"/> class + /// with the specified contract name, metadata and exported value getter. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="Export"/>. + /// </param> + /// <param name="metadata"> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="Export"/>; or <see langword="null"/> to set the + /// <see cref="Metadata"/> property to an empty, read-only + /// <see cref="IDictionary{TKey, TValue}"/>. + /// </param> + /// <param name="exportedValueGetter"> + /// A <see cref="Func{T}"/> that is called to create the exported value of the + /// <see cref="Export"/>. This allows the creation of the object to be delayed. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="contractName"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exportedValueGetter"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="contractName"/> is an empty string (""). + /// </exception> + public Export(string contractName, IDictionary<string, object> metadata, Func<object> exportedValueGetter) + : this(new ExportDefinition(contractName, metadata), exportedValueGetter) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="Export"/> class + /// with the specified export definition and exported value getter. + /// </summary> + /// <param name="definition"> + /// An <see cref="ExportDefinition"/> that describes the contract that the + /// <see cref="Export"/> satisfies. + /// </param> + /// <param name="exportedValueGetter"> + /// A <see cref="Func{T}"/> that is called to create the exported value of the + /// <see cref="Export"/>. This allows the creation of the object to be delayed. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="definition"/> is <see langword="null"/>. + /// <para> + /// -or- + /// </para> + /// <paramref name="exportedValueGetter"/> is <see langword="null"/>. + /// </exception> + public Export(ExportDefinition definition, Func<object> exportedValueGetter) + { + Requires.NotNull(definition, "definition"); + Requires.NotNull(exportedValueGetter, "exportedValueGetter"); + + this._definition = definition; + this._exportedValueGetter = exportedValueGetter; + } + + /// <summary> + /// Gets the definition that describes the contract that the export satisfies. + /// </summary> + /// <value> + /// An <see cref="ExportDefinition"/> that describes the contract that + /// the <see cref="Export"/> satisfies. + /// </value> + /// <exception cref="NotImplementedException"> + /// This property was not overridden by a derived class. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return + /// <see langword="null"/>. + /// </note> + /// </remarks> + public virtual ExportDefinition Definition + { + get + { + Contract.Ensures(Contract.Result<ExportDefinition>() != null); + + if (_definition != null) + { + return _definition; + } + + throw ExceptionBuilder.CreateNotOverriddenByDerived("Definition"); + } + } + + /// <summary> + /// Gets the metadata of the export. + /// </summary> + /// <value> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="Export"/>. + /// </value> + /// <exception cref="NotImplementedException"> + /// The <see cref="Definition"/> property was not overridden by a derived class. + /// </exception> + /// <remarks> + /// <para> + /// This property returns the value of <see cref="ExportDefinition.Metadata"/> + /// of the <see cref="Definition"/> property. + /// </para> + /// </remarks> + public IDictionary<string, object> Metadata + { + get + { + Contract.Ensures(Contract.Result<IDictionary<string, object>>() != null); + + return Definition.Metadata; + } + } + + /// <summary> + /// Returns the exported value of the export. + /// </summary> + /// <returns> + /// The exported <see cref="Object"/> of the <see cref="Export"/>. + /// </returns> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="CompositionContractMismatchException"> + /// The current instance is an instance of <see cref="Lazy{T}"/> and the underlying + /// exported value cannot be cast to <c>T</c>. + /// </exception> + /// <exception cref="NotImplementedException"> + /// The <see cref="GetExportedValueCore"/> method was not overridden by a derived class. + /// </exception> + public object Value + { + get + { + // NOTE : the logic below guarantees that the value will be set exactly once. It DOES NOT, however, guarantee that GetExportedValueCore() will be executed + // more than once, as locking would be required for that. The said locking is problematic, as we can't reliable call 3rd party code under a lock. + if (this._exportedValue == Export._EmptyValue) + { + object exportedValue = this.GetExportedValueCore(); + + // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. +#pragma warning disable 420 + Interlocked.CompareExchange(ref this._exportedValue, exportedValue, Export._EmptyValue); +#pragma warning restore 420 + } + + return this._exportedValue; + } + } + + /// <summary> + /// Returns the exported value of the export. + /// </summary> + /// <returns> + /// The exported <see cref="Object"/> of the <see cref="Export"/>. + /// </returns> + /// <exception cref="CompositionException"> + /// An error occurred during composition. <see cref="CompositionException.Errors"/> will + /// contain a collection of errors that occurred. + /// </exception> + /// <exception cref="CompositionContractMismatchException"> + /// The current instance is an instance of <see cref="Lazy{T}"/> and the underlying + /// exported value cannot be cast to <c>T</c>. + /// </exception> + /// <exception cref="NotImplementedException"> + /// The method was not overridden by a derived class. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this method should never return + /// <see langword="null"/>. + /// </note> + /// </remarks> + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + protected virtual object GetExportedValueCore() + { + if (this._exportedValueGetter != null) + { + return this._exportedValueGetter.Invoke(); + } + + throw ExceptionBuilder.CreateNotOverriddenByDerived("GetExportedValueCore"); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ExportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ExportDefinition.cs new file mode 100644 index 00000000000..6c7d1b1ccb7 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ExportDefinition.cs @@ -0,0 +1,139 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using Microsoft.Internal; +using System.Diagnostics.Contracts; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Describes the contract that an <see cref="Export"/> object satisfies. + /// </summary> + public class ExportDefinition + { + // Unlike contract name, metadata has a sensible default; set it to an empty bag, + // so that derived definitions only need to override ContractName by default. + private readonly IDictionary<string, object> _metadata = MetadataServices.EmptyMetadata; + private readonly string _contractName; + + /// <summary> + /// Initializes a new instance of the <see cref="ExportDefinition"/> class. + /// </summary> + /// <remarks> + /// <note type="inheritinfo"> + /// Derived types calling this constructor must override <see cref="ContractName"/> + /// and optionally, <see cref="Metadata"/>. By default, <see cref="Metadata"/> + /// returns an empty, read-only dictionary. + /// </note> + /// </remarks> + protected ExportDefinition() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ExportDefinition"/> class with + /// the specified contract name and metadata. + /// </summary> + /// <param name="contractName"> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="ExportDefinition"/>. + /// </param> + /// <param name="metadata"> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="ExportDefinition"/>; or <see langword="null"/> to set the + /// <see cref="Metadata"/> property to an empty, read-only + /// <see cref="IDictionary{TKey, TValue}"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="contractName"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="contractName"/> is an empty string (""). + /// </exception> + public ExportDefinition(string contractName, IDictionary<string, object> metadata) + { + Requires.NotNullOrEmpty(contractName, "contractName"); + + _contractName = contractName; + + if (metadata != null) + { + _metadata = metadata.AsReadOnly(); + } + } + + /// <summary> + /// Gets the contract name of the export definition. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the contract name of the + /// <see cref="ExportDefinition"/>. + /// </value> + /// <exception cref="NotImplementedException"> + /// The property was not overridden by a derived class. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/> + /// or an empty string (""). + /// </note> + /// </remarks> + public virtual string ContractName + { + get + { + Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>())); + + if (_contractName != null) + { + return _contractName; + } + + throw ExceptionBuilder.CreateNotOverriddenByDerived("ContractName"); + } + } + + /// <summary> + /// Gets the metadata of the export definition. + /// </summary> + /// <value> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="ExportDefinition"/>. The default is an empty, read-only + /// <see cref="IDictionary{TKey, TValue}"/>. + /// </value> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// Overriders of this property should return a read-only + /// <see cref="IDictionary{TKey, TValue}"/> object with a case-sensitive, + /// non-linguistic comparer, such as <see cref="StringComparer.Ordinal"/>, + /// and should never return <see langword="null"/>. + /// If the <see cref="ExportDefinition"/> does not contain metadata + /// return an empty <see cref="IDictionary{TKey, TValue}"/> instead. + /// </note> + /// </para> + /// </remarks> + public virtual IDictionary<string, object> Metadata + { + get + { + Contract.Ensures(Contract.Result<IDictionary<string, object>>() != null); + + return _metadata; + } + } + + /// <summary> + /// Returns a string representation of the export definition. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the value of the <see cref="ContractName"/> property. + /// </returns> + public override string ToString() + { + return this.ContractName; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ExportedDelegate.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ExportedDelegate.cs new file mode 100644 index 00000000000..98c120987f9 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ExportedDelegate.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Microsoft.Internal; +using System.Linq.Expressions; + +namespace System.ComponentModel.Composition.Primitives +{ + [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] + public class ExportedDelegate + { + private object _instance; + private MethodInfo _method; + + protected ExportedDelegate() { } + +#if FEATURE_CAS_APTCA + [System.Security.SecurityCritical] +#endif //FEATURE_CAS_APTCA + public ExportedDelegate(object instance, MethodInfo method) + { + Requires.NotNull(method, "method"); + + this._instance = instance; + this._method = method; + } + + public virtual Delegate CreateDelegate(Type delegateType) + { + Requires.NotNull(delegateType, "delegateType"); + + if (delegateType == typeof(Delegate) || delegateType == typeof(MulticastDelegate)) + { + delegateType = this.CreateStandardDelegateType(); + } + + return Delegate.CreateDelegate(delegateType, this._instance, this._method, false); + } + + private Type CreateStandardDelegateType() + { + ParameterInfo[] parameters = this._method.GetParameters(); + + // This array should contains a lit of all argument types, and the last one is the return type (could be void) + Type[] parameterTypes = new Type[parameters.Length + 1]; + parameterTypes[parameters.Length] = this._method.ReturnType; + for (int i = 0; i < parameters.Length; i++ ) + { + parameterTypes[i] = parameters[i].ParameterType; + } + + return Expression.GetDelegateType(parameterTypes); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ICompositionElement.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ICompositionElement.cs new file mode 100644 index 00000000000..42941dfc63d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ICompositionElement.cs @@ -0,0 +1,48 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.Contracts; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Represents an element that participates in composition. + /// </summary> +#if CONTRACTS_FULL + [ContractClass(typeof(ICompositionElementContract))] +#endif + public interface ICompositionElement + { + /// <summary> + /// Gets the display name of the composition element. + /// </summary> + /// <value> + /// A <see cref="String"/> containing a human-readable display name of the <see cref="ICompositionElement"/>. + /// </value> + /// <remarks> + /// <note type="implementnotes"> + /// Implementors of this property should never return <see langword="null"/> or an empty + /// string (""). + /// </note> + /// </remarks> + string DisplayName + { + get; + } + + /// <summary> + /// Gets the composition element from which the current composition element + /// originated. + /// </summary> + /// <value> + /// A <see cref="ICompositionElement"/> from which the current + /// <see cref="ICompositionElement"/> originated, or <see langword="null"/> + /// if the <see cref="ICompositionElement"/> is the root composition element. + /// </value> + ICompositionElement Origin + { + get; + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/IPartCreatorImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/IPartCreatorImportDefinition.cs new file mode 100644 index 00000000000..27ac0340a67 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/IPartCreatorImportDefinition.cs @@ -0,0 +1,12 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition.Primitives +{ + internal interface IPartCreatorImportDefinition + { + ContractBasedImportDefinition ProductImportDefinition { get; } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ImportCardinality.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ImportCardinality.cs new file mode 100644 index 00000000000..5ce945f174d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ImportCardinality.cs @@ -0,0 +1,28 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Indicates the cardinality of the <see cref="Export"/> objects required by an <see cref="ImportDefinition"/>. + /// </summary> + public enum ImportCardinality + { + /// <summary> + /// Zero or one <see cref="Export"/> objects are required by an <see cref="ImportDefinition"/>. + /// </summary> + ZeroOrOne = 0, + + /// <summary> + /// Exactly one <see cref="Export"/> object is required by an <see cref="ImportDefinition"/>. + /// </summary> + ExactlyOne = 1, + + /// <summary> + /// Zero or more <see cref="Export"/> objects are required by an <see cref="ImportDefinition"/>. + /// </summary> + ZeroOrMore = 2, + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ImportDefinition.cs new file mode 100644 index 00000000000..a8e042b5921 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/ImportDefinition.cs @@ -0,0 +1,291 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq.Expressions; +using Microsoft.Internal; +using System.Diagnostics.Contracts; +using System.Collections; +using System.Collections.Generic; + +namespace System.ComponentModel.Composition.Primitives +{ + /// <summary> + /// Represents an import required by a <see cref="ComposablePart"/> object. + /// </summary> + public class ImportDefinition + { + internal static readonly string EmptyContractName = string.Empty; + private readonly Expression<Func<ExportDefinition, bool>> _constraint; + private readonly ImportCardinality _cardinality = ImportCardinality.ExactlyOne; + private readonly string _contractName = EmptyContractName; + private readonly bool _isRecomposable; + private readonly bool _isPrerequisite = true; + private Func<ExportDefinition, bool> _compiledConstraint; + private readonly IDictionary<string, object> _metadata = MetadataServices.EmptyMetadata; + + /// <summary> + /// Initializes a new instance of the <see cref="ImportDefinition"/> class. + /// </summary> + /// <remarks> + /// <note type="inheritinfo"> + /// Derived types calling this constructor must override the <see cref="Constraint"/> + /// property, and optionally, the <see cref="Cardinality"/>, <see cref="IsPrerequisite"/> + /// and <see cref="IsRecomposable"/> + /// properties. + /// </note> + /// </remarks> + protected ImportDefinition() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="ImportDefinition"/> class + /// with the specified constraint, cardinality, value indicating if the import + /// definition is recomposable and a value indicating if the import definition + /// is a prerequisite. + /// </summary> + /// <param name="constraint"> + /// A <see cref="Expression{TDelegate}"/> containing a <see cref="Func{T, TResult}"/> + /// that defines the conditions that must be matched for the <see cref="ImportDefinition"/> + /// to be satisfied by an <see cref="Export"/>. + /// </param> + /// <param name="contractName"> + /// The contract name of the export that this import is interested in. The contract name + /// property is used as guidance and not automatically enforced in the constraint. If + /// the contract name is a required in the constraint then it should be added to the constraint + /// by the caller of this constructor. + /// </param> + /// <param name="cardinality"> + /// One of the <see cref="ImportCardinality"/> values indicating the + /// cardinality of the <see cref="Export"/> objects required by the + /// <see cref="ImportDefinition"/>. + /// </param> + /// <param name="isRecomposable"> + /// <see langword="true"/> if the <see cref="ImportDefinition"/> can be satisfied + /// multiple times throughout the lifetime of a <see cref="ComposablePart"/>, otherwise, + /// <see langword="false"/>. + /// </param> + /// <param name="isPrerequisite"> + /// <see langword="true"/> if the <see cref="ImportDefinition"/> is required to be + /// satisfied before a <see cref="ComposablePart"/> can start producing exported + /// objects; otherwise, <see langword="false"/>. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="constraint"/> is <see langword="null"/>. + /// </exception> + /// <exception cref="ArgumentException"> + /// <paramref name="cardinality"/> is not one of the <see cref="ImportCardinality"/> + /// values. + /// </exception> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public ImportDefinition(Expression<Func<ExportDefinition, bool>> constraint, string contractName, ImportCardinality cardinality, bool isRecomposable, bool isPrerequisite) + : this(contractName, cardinality, isRecomposable, isPrerequisite, MetadataServices.EmptyMetadata) + { + Requires.NotNull(constraint, "constraint"); + + this._constraint = constraint; + } + + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public ImportDefinition(Expression<Func<ExportDefinition, bool>> constraint, string contractName, ImportCardinality cardinality, bool isRecomposable, bool isPrerequisite, IDictionary<string, object> metadata) + : this(contractName, cardinality, isRecomposable, isPrerequisite, metadata) + { + Requires.NotNull(constraint, "constraint"); + + this._constraint = constraint; + } + + internal ImportDefinition(string contractName, ImportCardinality cardinality, bool isRecomposable, bool isPrerequisite, IDictionary<string, object> metadata) + { + if ( + (cardinality != ImportCardinality.ExactlyOne) && + (cardinality != ImportCardinality.ZeroOrMore) && + (cardinality != ImportCardinality.ZeroOrOne) + ) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.ArgumentOutOfRange_InvalidEnum, "cardinality", cardinality, typeof(ImportCardinality).Name), "cardinality"); + } + + this._contractName = contractName ?? EmptyContractName; + this._cardinality = cardinality; + this._isRecomposable = isRecomposable; + this._isPrerequisite = isPrerequisite; + + if (metadata != null) + { + this._metadata = metadata; + } + } + + /// <summary> + /// Gets the contract name of the export required by the import definition. + /// </summary> + /// <value> + /// A <see cref="String"/> containing the contract name of the <see cref="Export"/> + /// required by the <see cref="ContractBasedImportDefinition"/>. This property should + /// return <see cref="String.Empty"/> for imports that do not require a specific + /// contract name. + /// </value> + public virtual string ContractName + { + get + { + Contract.Ensures(Contract.Result<string>() != null); + + return this._contractName; + } + } + + /// <summary> + /// Gets the metadata of the import definition. + /// </summary> + /// <value> + /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the + /// <see cref="ExportDefinition"/>. The default is an empty, read-only + /// <see cref="IDictionary{TKey, TValue}"/>. + /// </value> + /// <remarks> + /// <para> + /// <note type="inheritinfo"> + /// Overriders of this property should return a read-only + /// <see cref="IDictionary{TKey, TValue}"/> object with a case-sensitive, + /// non-linguistic comparer, such as <see cref="StringComparer.Ordinal"/>, + /// and should never return <see langword="null"/>. + /// If the <see cref="ImportDefinition"/> does not contain metadata + /// return an empty <see cref="IDictionary{TKey, TValue}"/> instead. + /// </note> + /// </para> + /// </remarks> + public virtual IDictionary<string, object> Metadata + { + get + { + Contract.Ensures(Contract.Result<IDictionary<string, object>>() != null); + + return _metadata; + } + } + + /// <summary> + /// Gets the cardinality of the exports required by the import definition. + /// </summary> + /// <value> + /// One of the <see cref="ImportCardinality"/> values indicating the + /// cardinality of the <see cref="Export"/> objects required by the + /// <see cref="ImportDefinition"/>. The default is + /// <see cref="ImportCardinality.ExactlyOne"/> + /// </value> + public virtual ImportCardinality Cardinality + { + get { return this._cardinality; } + } + + /// <summary> + /// Gets an expression that defines conditions that must be matched for the import + /// described by the import definition to be satisfied. + /// </summary> + /// <returns> + /// A <see cref="Expression{TDelegate}"/> containing a <see cref="Func{T, TResult}"/> + /// that defines the conditions that must be matched for the + /// <see cref="ImportDefinition"/> to be satisfied by an <see cref="Export"/>. + /// </returns> + /// <exception cref="NotImplementedException"> + /// The property was not overridden by a derived class. + /// </exception> + /// <remarks> + /// <note type="inheritinfo"> + /// Overriders of this property should never return <see langword="null"/>. + /// </note> + /// </remarks> + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public virtual Expression<Func<ExportDefinition, bool>> Constraint + { + get + { + Contract.Ensures(Contract.Result<Expression<Func<ExportDefinition, bool>>>() != null); + + if (this._constraint != null) + { + return this._constraint; + } + + throw ExceptionBuilder.CreateNotOverriddenByDerived("Constraint"); + } + } + + /// <summary> + /// Gets a value indicating whether the import definition is required to be + /// satisfied before a part can start producing exported values. + /// </summary> + /// <value> + /// <see langword="true"/> if the <see cref="ImportDefinition"/> is required to be + /// satisfied before a <see cref="ComposablePart"/> can start producing exported + /// objects; otherwise, <see langword="false"/>. The default is <see langword="true"/>. + /// </value> + public virtual bool IsPrerequisite + { + get { return this._isPrerequisite; } + } + + /// <summary> + /// Gets a value indicating whether the import definition can be satisfied multiple times. + /// </summary> + /// <value> + /// <see langword="true"/> if the <see cref="ImportDefinition"/> can be satisfied + /// multiple times throughout the lifetime of a <see cref="ComposablePart"/>, otherwise, + /// <see langword="false"/>. The default is <see langword="false"/>. + /// </value> + public virtual bool IsRecomposable + { + get { return this._isRecomposable; } + } + + /// <summary> + /// Executes of the constraint provided by the <see cref="Constraint"/> property + /// against a given <see cref="ExportDefinition"/> to determine if this + /// <see cref="ImportDefinition"/> can be satisfied by the given <see cref="Export"/>. + /// </summary> + /// <param name="exportDefinition"> + /// A definition for a <see cref="Export"/> used to determine if it satisfies the + /// requirements for this <see cref="ImportDefinition"/>. + /// </param> + /// <returns> + /// <see langword="True"/> if the <see cref="Export"/> satisfies the requirements for + /// this <see cref="ImportDefinition"/>, otherwise returns <see langword="False"/>. + /// </returns> + /// <remarks> + /// <note type="inheritinfo"> + /// Overrides of this method can provide a more optimized execution of the + /// <see cref="Constraint"/> property but the result should remain consistent. + /// </note> + /// </remarks> + /// <exception cref="ArgumentNullException"> + /// <paramref name="exportDefinition"/> is <see langword="null"/>. + /// </exception> + public virtual bool IsConstraintSatisfiedBy(ExportDefinition exportDefinition) + { + Requires.NotNull(exportDefinition, "exportDefinition"); + + if (this._compiledConstraint == null) + { + this._compiledConstraint = this.Constraint.Compile(); + } + + return this._compiledConstraint.Invoke(exportDefinition); + } + + /// <summary> + /// Returns a string representation of the import definition. + /// </summary> + /// <returns> + /// A <see cref="String"/> containing the value of the <see cref="Constraint"/> property. + /// </returns> + public override string ToString() + { + return this.Constraint.Body.ToString(); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/PrimitivesServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/PrimitivesServices.cs new file mode 100644 index 00000000000..2cecbd86332 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/PrimitivesServices.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.ReflectionModel; + +namespace System.ComponentModel.Composition.Primitives +{ + internal static class PrimitivesServices + { + public static bool IsGeneric(this ComposablePartDefinition part) + { + return part.Metadata.GetValue<bool>(CompositionConstants.IsGenericPartMetadataName); + } + + public static ImportDefinition GetProductImportDefinition(this ImportDefinition import) + { + IPartCreatorImportDefinition partCreatorDefinition = import as IPartCreatorImportDefinition; + + if (partCreatorDefinition != null) + { + return partCreatorDefinition.ProductImportDefinition; + } + else + { + return import; + } + } + + internal static IEnumerable<string> GetCandidateContractNames(this ImportDefinition import, ComposablePartDefinition part) + { + import = import.GetProductImportDefinition(); + string contractName = import.ContractName; + string genericContractName = import.Metadata.GetValue<string>(CompositionConstants.GenericContractMetadataName); + int[] importParametersOrder = import.Metadata.GetValue<int[]>(CompositionConstants.GenericImportParametersOrderMetadataName); + if (importParametersOrder != null) + { + int partArity = part.Metadata.GetValue<int>(CompositionConstants.GenericPartArityMetadataName); + if (partArity > 0) + { + contractName = GenericServices.GetGenericName(contractName, importParametersOrder, partArity); + } + } + + yield return contractName; + if (!string.IsNullOrEmpty(genericContractName)) + { + yield return genericContractName; + } + } + + + internal static bool IsImportDependentOnPart(this ImportDefinition import, ComposablePartDefinition part, ExportDefinition export, bool expandGenerics) + { + import = import.GetProductImportDefinition(); + if (expandGenerics) + { + return part.GetExports(import).Any(); + } + else + { + return TranslateImport(import, part).IsConstraintSatisfiedBy(export); + } + } + + private static ImportDefinition TranslateImport(ImportDefinition import, ComposablePartDefinition part) + { + ContractBasedImportDefinition contractBasedImport = import as ContractBasedImportDefinition; + if (contractBasedImport == null) + { + return import; + } + + int[] importParametersOrder = contractBasedImport.Metadata.GetValue<int[]>(CompositionConstants.GenericImportParametersOrderMetadataName); + if (importParametersOrder == null) + { + return import; + } + + int partArity = part.Metadata.GetValue<int>(CompositionConstants.GenericPartArityMetadataName); + if (partArity == 0) + { + return import; + } + + string contractName = GenericServices.GetGenericName(contractBasedImport.ContractName, importParametersOrder, partArity); + string requiredTypeIdentity = GenericServices.GetGenericName(contractBasedImport.RequiredTypeIdentity, importParametersOrder, partArity); + return new ContractBasedImportDefinition( + contractName, + requiredTypeIdentity, + contractBasedImport.RequiredMetadata, + contractBasedImport.Cardinality, + contractBasedImport.IsRecomposable, + false, + contractBasedImport.RequiredCreationPolicy, + contractBasedImport.Metadata); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/SerializableCompositionElement.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/SerializableCompositionElement.cs new file mode 100644 index 00000000000..08c90076440 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Primitives/SerializableCompositionElement.cs @@ -0,0 +1,57 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.Primitives +{ + // As most objects that implement ICompositionElement (such as Export, ComposablePart, + // ComposablePartCatalog, etc) are not serializable, this class is used as a serializable + // placeholder for these types when ICompositionElement is used within serializable types, + // such as CompositionException, CompositionIssue, etc. + [Serializable] + internal class SerializableCompositionElement : ICompositionElement + { + private readonly string _displayName; + private readonly ICompositionElement _origin; + + public SerializableCompositionElement(string displayName, ICompositionElement origin) + { +#if FEATURE_SERIALIZATION + Assumes.IsTrue(origin == null || origin.GetType().IsSerializable); +#endif + this._displayName = displayName ?? string.Empty; + this._origin = origin; + } + + public string DisplayName + { + get { return this._displayName; } + } + + public ICompositionElement Origin + { + get { return this._origin; } + } + + public override string ToString() + { + return this.DisplayName; + } + + public static ICompositionElement FromICompositionElement(ICompositionElement element) + { + if (element == null) + { // Null is always serializable + + return null; + } + + ICompositionElement origin = FromICompositionElement(element.Origin); + + // Otherwise, we need to create a serializable wrapper + return new SerializableCompositionElement(element.DisplayName, origin); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/DisposableReflectionComposablePart.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/DisposableReflectionComposablePart.cs new file mode 100644 index 00000000000..c883d1d6dbb --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/DisposableReflectionComposablePart.cs @@ -0,0 +1,57 @@ + +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal sealed class DisposableReflectionComposablePart : ReflectionComposablePart, IDisposable + { + private volatile int _isDisposed = 0; + + public DisposableReflectionComposablePart(ReflectionComposablePartDefinition definition) + : base(definition) + { + } + + protected override void ReleaseInstanceIfNecessary(object instance) + { + IDisposable disposable = instance as IDisposable; + if (disposable != null) + { + disposable.Dispose(); + } + } + + protected override void EnsureRunning() + { + base.EnsureRunning(); + if (this._isDisposed == 1) + { + throw ExceptionBuilder.CreateObjectDisposed(this); + } + } + + void IDisposable.Dispose() + { + // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. +#pragma warning disable 420 + if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) +#pragma warning restore 420 + { + this.ReleaseInstanceIfNecessary(this.CachedInstance); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportfactoryCreator.LifetimeContext.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportfactoryCreator.LifetimeContext.cs new file mode 100644 index 00000000000..a1a2a85f8bd --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportfactoryCreator.LifetimeContext.cs @@ -0,0 +1,80 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal sealed partial class ExportFactoryCreator + { + private class LifetimeContext + { + static Type[] types = { typeof(ComposablePartDefinition) }; + public Func<ComposablePartDefinition, bool> CatalogFilter { get; private set; } + + public void SetInstance(object instance) + { + Assumes.NotNull(instance); + + var methodInfo = instance.GetType().GetMethod("IncludeInScopedCatalog", BindingFlags.NonPublic | BindingFlags.Instance, null, types, null); + CatalogFilter = (Func<ComposablePartDefinition, bool>)Delegate.CreateDelegate(typeof(Func<ComposablePartDefinition, bool>), instance, methodInfo); + } + + public Tuple<T, Action> GetExportLifetimeContextFromExport<T>(Export export) + { + T exportedValue; + Action disposeAction; + IDisposable disposable = null; + + CatalogExportProvider.ScopeFactoryExport scopeFactoryExport = export as CatalogExportProvider.ScopeFactoryExport; + + if (scopeFactoryExport != null) + { + // Scoped PartCreatorExport + Export exportProduct = scopeFactoryExport.CreateExportProduct(CatalogFilter); + exportedValue = ExportServices.GetCastedExportedValue<T>(exportProduct); + disposable = exportProduct as IDisposable; + } + else + { + CatalogExportProvider.FactoryExport factoryExport = export as CatalogExportProvider.FactoryExport; + + if (factoryExport != null) + { + // PartCreatorExport is the more optimized route + Export exportProduct = factoryExport.CreateExportProduct(); + exportedValue = ExportServices.GetCastedExportedValue<T>(exportProduct); + disposable = exportProduct as IDisposable; + } + else + { + // If it comes from somewhere else we walk through the ComposablePartDefinition + var factoryPartDefinition = ExportServices.GetCastedExportedValue<ComposablePartDefinition>(export); + var part = factoryPartDefinition.CreatePart(); + var exportDef = factoryPartDefinition.ExportDefinitions.Single(); + + exportedValue = ExportServices.CastExportedValue<T>(part.ToElement(), part.GetExportedValue(exportDef)); + disposable = part as IDisposable; + } + } + + if (disposable != null) + { + disposeAction = () => disposable.Dispose(); + } + else + { + disposeAction = () => { }; + } + + return new Tuple<T, Action>(exportedValue, disposeAction); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportfactoryCreator.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportfactoryCreator.cs new file mode 100644 index 00000000000..35fa8516a78 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportfactoryCreator.cs @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal sealed partial class ExportFactoryCreator + { + private static readonly MethodInfo _createStronglyTypedExportFactoryOfT = typeof(ExportFactoryCreator).GetMethod("CreateStronglyTypedExportFactoryOfT", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + private static readonly MethodInfo _createStronglyTypedExportFactoryOfTM = typeof(ExportFactoryCreator).GetMethod("CreateStronglyTypedExportFactoryOfTM", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + private Type _exportFactoryType; + + public ExportFactoryCreator(Type exportFactoryType) + { + Assumes.NotNull(exportFactoryType); + + this._exportFactoryType = exportFactoryType; + } + + public Func<Export, object> CreateStronglyTypedExportFactoryFactory(Type exportType, Type metadataViewType) + { + MethodInfo genericMethod = null; + if (metadataViewType == null) + { + genericMethod = _createStronglyTypedExportFactoryOfT.MakeGenericMethod(exportType); + } + else + { + genericMethod = _createStronglyTypedExportFactoryOfTM.MakeGenericMethod(exportType, metadataViewType); + } + + Assumes.NotNull(genericMethod); + Func<Export, object> exportFactoryFactory = (Func<Export, object>)Delegate.CreateDelegate(typeof(Func<Export, object>), this, genericMethod); + return (e) => exportFactoryFactory.Invoke(e); + } + + private object CreateStronglyTypedExportFactoryOfT<T>(Export export) + { + Type[] typeArgs = { typeof(T) }; + Type constructed = this._exportFactoryType.MakeGenericType(typeArgs); + + var lifetimeContext = new LifetimeContext(); + + Func<Tuple<T, Action>> exportLifetimeContextCreator = () => lifetimeContext.GetExportLifetimeContextFromExport<T>(export); + object[] args = { exportLifetimeContextCreator }; + + var instance = Activator.CreateInstance(constructed, args); + lifetimeContext.SetInstance(instance); + + return instance; + } + + private object CreateStronglyTypedExportFactoryOfTM<T, M>(Export export) + { + Type[] typeArgs = { typeof(T), typeof(M) }; + Type constructed = this._exportFactoryType.MakeGenericType(typeArgs); + + var lifetimeContext = new LifetimeContext(); + + Func<Tuple<T, Action>> exportLifetimeContextCreator = () => lifetimeContext.GetExportLifetimeContextFromExport<T>(export); + var metadataView = AttributedModelServices.GetMetadataView<M>(export.Metadata); + object[] args = { exportLifetimeContextCreator, metadataView }; + + var instance = Activator.CreateInstance(constructed, args); + lifetimeContext.SetInstance(instance); + + return instance; + } + + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportingMember.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportingMember.cs new file mode 100644 index 00000000000..3276c7b47bf --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ExportingMember.cs @@ -0,0 +1,103 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ExportingMember + { + private readonly ExportDefinition _definition; + private readonly ReflectionMember _member; + private object _cachedValue = null; + private volatile bool _isValueCached = false; + + public ExportingMember(ExportDefinition definition, ReflectionMember member) + { + Assumes.NotNull(definition, member); + + this._definition = definition; + this._member = member; + } + + public bool RequiresInstance + { + get { return _member.RequiresInstance; } + } + + public ExportDefinition Definition + { + get { return _definition; } + } + + public object GetExportedValue(object instance, object @lock) + { + this.EnsureReadable(); + + if (!this._isValueCached) + { + object exportedValue; + try + { + exportedValue = this._member.GetValue(instance); + } + catch (TargetInvocationException exception) + { // Member threw an exception. Avoid letting this + // leak out as a 'raw' unhandled exception, instead, + // we'll add some context and rethrow. + + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ExportThrewException, + this._member.GetDisplayName()), + Definition.ToElement(), + exception.InnerException); + } + catch (TargetParameterCountException exception) + { + // Exception was a TargetParameterCountException this occurs when we try to get an Indexer that has an Export + // this is not supported in MEF currently. Ideally we would validate against it, however, we already shipped + // so we will turn it into a ComposablePartException instead, that they should already be prepared for + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ExportNotValidOnIndexers, + this._member.GetDisplayName()), + Definition.ToElement(), + exception.InnerException); + } + + lock (@lock) + { + if (!this._isValueCached) + { + this._cachedValue = exportedValue; + Thread.MemoryBarrier(); + + this._isValueCached = true; + } + } + } + + return this._cachedValue; + } + + private void EnsureReadable() + { + if (!this._member.CanRead) + { // Property does not have a getter + + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ExportNotReadable, + this._member.GetDisplayName()), + Definition.ToElement()); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs new file mode 100644 index 00000000000..559b09e5146 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericServices.cs @@ -0,0 +1,216 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Linq; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; +using System.Collections.Generic; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal static class GenericServices + { + internal static IList<Type> GetPureGenericParameters(this Type type) + { + Assumes.NotNull(type); + + if (type.IsGenericType && type.ContainsGenericParameters) + { + List<Type> pureGenericParameters = new List<Type>(); + TraverseGenericType(type, (Type t) => + { + if (t.IsGenericParameter) + { + pureGenericParameters.Add(t); + } + }); + return pureGenericParameters; + } + else + { + return Type.EmptyTypes; + } + } + + internal static int GetPureGenericArity(this Type type) + { + Assumes.NotNull(type); + + int genericArity = 0; + if (type.IsGenericType && type.ContainsGenericParameters) + { + List<Type> pureGenericParameters = new List<Type>(); + TraverseGenericType(type, (Type t) => + { + if (t.IsGenericParameter) + { + genericArity++; + } + }); + } + return genericArity; + } + + + + private static void TraverseGenericType(Type type, Action<Type> onType) + { + if (type.IsGenericType) + { + foreach(Type genericArgument in type.GetGenericArguments()) + { + TraverseGenericType(genericArgument, onType); + } + } + onType(type); + } + + public static int[] GetGenericParametersOrder(Type type) + { + return type.GetPureGenericParameters().Select(parameter => parameter.GenericParameterPosition).ToArray(); + } + + public static string GetGenericName(string originalGenericName, int[] genericParametersOrder, int genericArity) + { + string[] genericFormatArgs = new string[genericArity]; + for (int i = 0; i < genericParametersOrder.Length; i++) + { + genericFormatArgs[genericParametersOrder[i]] = string.Format(CultureInfo.InvariantCulture, "{{{0}}}", i); + } + return string.Format(CultureInfo.InvariantCulture, originalGenericName, genericFormatArgs); + } + + public static T[] Reorder<T>(T[] original, int[] genericParametersOrder) + { + T[] genericSpecialization = new T[genericParametersOrder.Length]; + for (int i = 0; i < genericParametersOrder.Length; i++) + { + genericSpecialization[i] = original[genericParametersOrder[i]]; + } + return genericSpecialization; + } + + + public static IEnumerable<Type> CreateTypeSpecializations(this Type[] types, Type[] specializationTypes) + { + if (types == null) + { + return null; + } + else + { + return types.Select(type => type.CreateTypeSpecialization(specializationTypes)); + } + } + + public static Type CreateTypeSpecialization(this Type type, Type[] specializationTypes) + { + if (!type.ContainsGenericParameters) + { + return type; + } + + if (type.IsGenericParameter) + { + // the only case when MakeGenericType won't work is when the 'type' represents a "naked" generic type + // in this case we simply grab the type with the proper index from the specializtion + return specializationTypes[type.GenericParameterPosition]; + } + else + { + Type[] typeGenericArguments = type.GetGenericArguments(); + Type[] subSpecialization = new Type[typeGenericArguments.Length]; + + for (int i = 0; i < typeGenericArguments.Length; i++) + { + Type typeGenericArgument = typeGenericArguments[i]; + subSpecialization[i] = typeGenericArgument.IsGenericParameter ? + specializationTypes[typeGenericArgument.GenericParameterPosition] : typeGenericArgument; + + } + + // and "close" the generic + return type.GetGenericTypeDefinition().MakeGenericType(subSpecialization); + } + + } + + public static bool CanSpecialize(Type type, IEnumerable<Type> constraints, GenericParameterAttributes attributes) + { + return CanSpecialize(type, constraints) && CanSpecialize(type, attributes); + } + + public static bool CanSpecialize(Type type, IEnumerable<Type> constraintTypes) + { + if (constraintTypes == null) + { + return true; + } + + // where T : IFoo + // a part of where T : struct is also handled here as T : ValueType + foreach (Type constraintType in constraintTypes) + { + if ((constraintType != null) && !constraintType.IsAssignableFrom(type)) + { + return false; + } + } + + return true; + } + + public static bool CanSpecialize(Type type, GenericParameterAttributes attributes) + { + if (attributes == GenericParameterAttributes.None) + { + return true; + } + + // where T : class + if ((attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0) + { + if (type.IsValueType) + { + return false; + } + } + + // where T : new + if ((attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0) + { + // value types always have default constructors + if (!type.IsValueType && (type.GetConstructor(Type.EmptyTypes) == null)) + { + return false; + } + } + + // where T : struct + if ((attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) + { + // must be a value type + if (!type.IsValueType) + { + return false; + } + + // Make sure that the type is not nullable + // this is salways guaranteed in C#, but other languages may be different + if (Nullable.GetUnderlyingType(type) != null) + { + return false; + } + } + + // all other fals indicate variance and don't place any actual restrictions on the generic parameters + // but rather how they should be used by the compiler + return true; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericSpecializationPartCreationInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericSpecializationPartCreationInfo.cs new file mode 100644 index 00000000000..776e6218e02 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/GenericSpecializationPartCreationInfo.cs @@ -0,0 +1,564 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Diagnostics.Contracts; +using System.Threading; +using System.ComponentModel.Composition.Hosting; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class GenericSpecializationPartCreationInfo : IReflectionPartCreationInfo + { + private readonly IReflectionPartCreationInfo _originalPartCreationInfo; + private readonly ReflectionComposablePartDefinition _originalPart; + private readonly Type[] _specialization; + private readonly string[] _specializationIdentities; + private IEnumerable<ExportDefinition> _exports; + private IEnumerable<ImportDefinition> _imports; + private readonly Lazy<Type> _lazyPartType; + private List<LazyMemberInfo> _members; + private List<Lazy<ParameterInfo>> _parameters; + private Dictionary<LazyMemberInfo, MemberInfo[]> _membersTable; + private Dictionary<Lazy<ParameterInfo>, ParameterInfo> _parametersTable; + private ConstructorInfo _constructor; + private object _lock = new object(); + + public GenericSpecializationPartCreationInfo(IReflectionPartCreationInfo originalPartCreationInfo, ReflectionComposablePartDefinition originalPart, Type[] specialization) + { + Assumes.NotNull(originalPartCreationInfo); + Assumes.NotNull(specialization); + Assumes.NotNull(originalPart); + + this._originalPartCreationInfo = originalPartCreationInfo; + this._originalPart = originalPart; + this._specialization = specialization; + this._specializationIdentities = new string[this._specialization.Length]; + for (int i = 0; i < this._specialization.Length; i++) + { + this._specializationIdentities[i] = AttributedModelServices.GetTypeIdentity(this._specialization[i]); + } + this._lazyPartType = new Lazy<Type>( + () => this._originalPartCreationInfo.GetPartType().MakeGenericType(specialization), + LazyThreadSafetyMode.PublicationOnly); + + } + + public ReflectionComposablePartDefinition OriginalPart + { + get + { + return this._originalPart; + } + } + + public Type GetPartType() + { + return this._lazyPartType.Value; + } + + public Lazy<Type> GetLazyPartType() + { + return this._lazyPartType; + } + + public ConstructorInfo GetConstructor() + { + if (this._constructor == null) + { + ConstructorInfo genericConstuctor = this._originalPartCreationInfo.GetConstructor(); + ConstructorInfo result = null; + if (genericConstuctor != null) + { + foreach (ConstructorInfo constructor in this.GetPartType().GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + if (constructor.MetadataToken == genericConstuctor.MetadataToken) + { + result = constructor; + break; + } + } + } + + Thread.MemoryBarrier(); + lock (this._lock) + { + if (this._constructor == null) + { + this._constructor = result; + } + } + } + + return this._constructor; + } + + public IDictionary<string, object> GetMetadata() + { + var originalMetadata = new Dictionary<string, object>(this._originalPartCreationInfo.GetMetadata(), StringComparers.MetadataKeyNames); + originalMetadata.Remove(CompositionConstants.IsGenericPartMetadataName); + originalMetadata.Remove(CompositionConstants.GenericPartArityMetadataName); + originalMetadata.Remove(CompositionConstants.GenericParameterConstraintsMetadataName); + originalMetadata.Remove(CompositionConstants.GenericParameterAttributesMetadataName); + + return originalMetadata; + } + + private MemberInfo[] GetAccessors(LazyMemberInfo originalLazyMember) + { + this.BuildTables(); + Assumes.NotNull(this._membersTable); + + return this._membersTable[originalLazyMember]; + } + + private ParameterInfo GetParameter(Lazy<ParameterInfo> originalParameter) + { + this.BuildTables(); + Assumes.NotNull(this._parametersTable); + + return this._parametersTable[originalParameter]; + } + + private void BuildTables() + { + if (this._membersTable != null) + { + return; + } + + this.PopulateImportsAndExports(); + + List<LazyMemberInfo> members = null; + List<Lazy<ParameterInfo>> parameters = null; + lock (this._lock) + { + if (this._membersTable == null) + { + members = this._members; + parameters = this._parameters; + + Assumes.NotNull(members); + } + } + + // + // Get all members that can be of interest and extract their MetadataTokens + // + Dictionary<LazyMemberInfo, MemberInfo[]> membersTable = this.BuildMembersTable(members); + Dictionary<Lazy<ParameterInfo>, ParameterInfo> parametersTable = this.BuildParametersTable(parameters); + + lock (this._lock) + { + if (this._membersTable == null) + { + this._membersTable = membersTable; + this._parametersTable = parametersTable; + + Thread.MemoryBarrier(); + + this._parameters = null; + this._members = null; + } + } + } + + + private Dictionary<LazyMemberInfo, MemberInfo[]> BuildMembersTable(List<LazyMemberInfo> members) + { + Assumes.NotNull(members); + + Dictionary<LazyMemberInfo, MemberInfo[]> membersTable = new Dictionary<LazyMemberInfo, MemberInfo[]>(); + Dictionary<int, MemberInfo> specializedPartMembers = new Dictionary<int, MemberInfo>(); + + Type closedGenericPartType = this.GetPartType(); + + specializedPartMembers[closedGenericPartType.MetadataToken] = closedGenericPartType; + foreach (MethodInfo method in closedGenericPartType.GetAllMethods()) + { + specializedPartMembers[method.MetadataToken] = method; + } + + foreach (FieldInfo field in closedGenericPartType.GetAllFields()) + { + specializedPartMembers[field.MetadataToken] = field; + } + + // + // Now go through the members table and resolve them into the new closed type based on the tokens + // + foreach (LazyMemberInfo lazyMemberInfo in members) + { + MemberInfo[] genericAccessors = lazyMemberInfo.GetAccessors(); + MemberInfo[] accessors = new MemberInfo[genericAccessors.Length]; + + for (int i = 0; i < genericAccessors.Length; i++) + { + // GENTODO - error case? Very unlikely, but still? + accessors[i] = (genericAccessors[i] != null) ? specializedPartMembers[genericAccessors[i].MetadataToken] : null; + } + + membersTable[lazyMemberInfo] = accessors; + } + + return membersTable; + } + + private Dictionary<Lazy<ParameterInfo>, ParameterInfo> BuildParametersTable(List<Lazy<ParameterInfo>> parameters) + { + if (parameters != null) + { + Dictionary<Lazy<ParameterInfo>, ParameterInfo> parametersTable = new Dictionary<Lazy<ParameterInfo>, ParameterInfo>(); + // GENTODO - error case + ParameterInfo[] constructorParameters = this.GetConstructor().GetParameters(); + foreach (var lazyParameter in parameters) + { + parametersTable[lazyParameter] = constructorParameters[lazyParameter.Value.Position]; + } + return parametersTable; + } + else + { + return null; + } + + } + + + private List<ImportDefinition> PopulateImports(List<LazyMemberInfo> members, List<Lazy<ParameterInfo>> parameters) + { + List<ImportDefinition> imports = new List<ImportDefinition>(); + + foreach (ImportDefinition originalImport in this._originalPartCreationInfo.GetImports()) + { + ReflectionImportDefinition reflectionImport = originalImport as ReflectionImportDefinition; + if (reflectionImport == null) + { + // we always ignore these + continue; + } + + imports.Add(this.TranslateImport(reflectionImport, members, parameters)); + } + + return imports; + } + + + private ImportDefinition TranslateImport(ReflectionImportDefinition reflectionImport, List<LazyMemberInfo> members, List<Lazy<ParameterInfo>> parameters) + { + bool isExportFactory = false; + ContractBasedImportDefinition productImport = reflectionImport; + + IPartCreatorImportDefinition exportFactoryImportDefinition = reflectionImport as IPartCreatorImportDefinition; + if (exportFactoryImportDefinition != null) + { + productImport = exportFactoryImportDefinition.ProductImportDefinition; + isExportFactory = true; + } + + string contractName = this.Translate(productImport.ContractName); + string requiredTypeIdentity = this.Translate(productImport.RequiredTypeIdentity); + IDictionary<string, object> metadata = this.TranslateImportMetadata(productImport); + + ReflectionMemberImportDefinition memberImport = reflectionImport as ReflectionMemberImportDefinition; + ImportDefinition import = null; + if (memberImport != null) + { + LazyMemberInfo lazyMember = memberImport.ImportingLazyMember; + LazyMemberInfo importingMember = new LazyMemberInfo(lazyMember.MemberType, () => GetAccessors(lazyMember)); + + if (isExportFactory) + { + import = new PartCreatorMemberImportDefinition( + importingMember, + ((ICompositionElement)memberImport).Origin, + new ContractBasedImportDefinition( + contractName, + requiredTypeIdentity, + productImport.RequiredMetadata, + productImport.Cardinality, + productImport.IsRecomposable, + false, + CreationPolicy.NonShared, + metadata)); + } + else + { + import = new ReflectionMemberImportDefinition( + importingMember, + contractName, + requiredTypeIdentity, + productImport.RequiredMetadata, + productImport.Cardinality, + productImport.IsRecomposable, + false, + productImport.RequiredCreationPolicy, + metadata, + ((ICompositionElement)memberImport).Origin); + } + + members.Add(lazyMember); + } + else + { + ReflectionParameterImportDefinition parameterImport = reflectionImport as ReflectionParameterImportDefinition; + Assumes.NotNull(parameterImport); + + Lazy<ParameterInfo> lazyParameter = parameterImport.ImportingLazyParameter; + Lazy<ParameterInfo> parameter = new Lazy<ParameterInfo>(() => GetParameter(lazyParameter)); + + if (isExportFactory) + { + import = new PartCreatorParameterImportDefinition( + parameter, + ((ICompositionElement)parameterImport).Origin, + new ContractBasedImportDefinition( + contractName, + requiredTypeIdentity, + productImport.RequiredMetadata, + productImport.Cardinality, + false, + true, + CreationPolicy.NonShared, + metadata)); + } + else + { + import = new ReflectionParameterImportDefinition( + parameter, + contractName, + requiredTypeIdentity, + productImport.RequiredMetadata, + productImport.Cardinality, + productImport.RequiredCreationPolicy, + metadata, + ((ICompositionElement)parameterImport).Origin); + } + + parameters.Add(lazyParameter); + } + + return import; + } + + private List<ExportDefinition> PopulateExports(List<LazyMemberInfo> members) + { + List<ExportDefinition> exports = new List<ExportDefinition>(); + + foreach (ExportDefinition originalExport in this._originalPartCreationInfo.GetExports()) + { + ReflectionMemberExportDefinition reflectionExport = originalExport as ReflectionMemberExportDefinition; + if (reflectionExport == null) + { + // we always ignore these + continue; + } + + exports.Add(this.TranslateExpot(reflectionExport, members)); + } + + return exports; + } + + public ExportDefinition TranslateExpot(ReflectionMemberExportDefinition reflectionExport, List<LazyMemberInfo> members) + { + ExportDefinition export = null; + LazyMemberInfo lazyMember = reflectionExport.ExportingLazyMember; + var capturedLazyMember = lazyMember; + var capturedReflectionExport = reflectionExport; + + string contractName = this.Translate(reflectionExport.ContractName, reflectionExport.Metadata.GetValue<int[]>(CompositionConstants.GenericExportParametersOrderMetadataName)); + + LazyMemberInfo exportingMember = new LazyMemberInfo(capturedLazyMember.MemberType, () => GetAccessors(capturedLazyMember)); + Lazy<IDictionary<string, object>> lazyMetadata = new Lazy<IDictionary<string, object>>(() => this.TranslateExportMetadata(capturedReflectionExport)); + + + + export = new ReflectionMemberExportDefinition( + exportingMember, + new LazyExportDefinition(contractName, lazyMetadata), + ((ICompositionElement)reflectionExport).Origin); + + members.Add(capturedLazyMember); + + return export; + } + + private string Translate(string originalValue, int[] genericParametersOrder) + { + if (genericParametersOrder != null) + { + string[] specializationIdentities = GenericServices.Reorder(this._specializationIdentities, genericParametersOrder); + return string.Format(CultureInfo.InvariantCulture, originalValue, specializationIdentities); + } + else + { + return Translate(originalValue); + } + } + + private string Translate(string originalValue) + { + return string.Format(CultureInfo.InvariantCulture, originalValue, this._specializationIdentities); + } + + private IDictionary<string, object> TranslateImportMetadata(ContractBasedImportDefinition originalImport) + { + int[] importParametersOrder = originalImport.Metadata.GetValue<int[]>(CompositionConstants.GenericImportParametersOrderMetadataName); + if (importParametersOrder != null) + { + Dictionary<string, object> metadata = new Dictionary<string, object>(originalImport.Metadata, StringComparers.MetadataKeyNames); + + // Get the newly re-qualified name of the generic contract and the subset of applicable types from the specialization + metadata[CompositionConstants.GenericContractMetadataName] = GenericServices.GetGenericName(originalImport.ContractName, importParametersOrder, this._specialization.Length); + metadata[CompositionConstants.GenericParametersMetadataName] = GenericServices.Reorder(this._specialization, importParametersOrder); + metadata.Remove(CompositionConstants.GenericImportParametersOrderMetadataName); + + return metadata.AsReadOnly(); + } + else + { + return originalImport.Metadata; + } + } + + private IDictionary<string, object> TranslateExportMetadata(ReflectionMemberExportDefinition originalExport) + { + Dictionary<string, object> metadata = new Dictionary<string, object>(originalExport.Metadata, StringComparers.MetadataKeyNames); + + string exportTypeIdentity = originalExport.Metadata.GetValue<string>(CompositionConstants.ExportTypeIdentityMetadataName); + if (!string.IsNullOrEmpty(exportTypeIdentity)) + { + metadata[CompositionConstants.ExportTypeIdentityMetadataName] = this.Translate(exportTypeIdentity, originalExport.Metadata.GetValue<int[]>(CompositionConstants.GenericExportParametersOrderMetadataName)); + } + metadata.Remove(CompositionConstants.GenericExportParametersOrderMetadataName); + + return metadata; + } + + private void PopulateImportsAndExports() + { + if ((this._exports == null) || (this._imports == null)) + { + List<LazyMemberInfo> members = new List<LazyMemberInfo>(); + List<Lazy<ParameterInfo>> parameters = new List<Lazy<ParameterInfo>>(); + + // we are very careful to not call any 3rd party code in either of these + var exports = this.PopulateExports(members); + var imports = this.PopulateImports(members, parameters); + Thread.MemoryBarrier(); + + lock (this._lock) + { + if ((this._exports == null) || (this._imports == null)) + { + this._members = members; + if (parameters.Count > 0) + { + this._parameters = parameters; + } + + this._exports = exports; + this._imports = imports; + } + } + } + } + + public IEnumerable<ExportDefinition> GetExports() + { + this.PopulateImportsAndExports(); + return this._exports; + } + + + public IEnumerable<ImportDefinition> GetImports() + { + this.PopulateImportsAndExports(); + return this._imports; + } + + public bool IsDisposalRequired + { + get { return this._originalPartCreationInfo.IsDisposalRequired; } + } + + public string DisplayName + { + get { return this.Translate(this._originalPartCreationInfo.DisplayName); } + } + + public ICompositionElement Origin + { + get { return this._originalPartCreationInfo.Origin; } + } + + public override bool Equals(object obj) + { + GenericSpecializationPartCreationInfo that = obj as GenericSpecializationPartCreationInfo; + if (that == null) + { + return false; + } + + return (this._originalPartCreationInfo.Equals(that._originalPartCreationInfo)) && + (this._specialization.IsArrayEqual(that._specialization)); + } + + public override int GetHashCode() + { + return this._originalPartCreationInfo.GetHashCode(); + } + + public static bool CanSpecialize(IDictionary<string, object> partMetadata, Type[] specialization) + { + int partArity = partMetadata.GetValue<int>(CompositionConstants.GenericPartArityMetadataName); + + if (partArity != specialization.Length) + { + return false; + } + + object[] genericParameterConstraints = partMetadata.GetValue<object[]>(CompositionConstants.GenericParameterConstraintsMetadataName); + GenericParameterAttributes[] genericParameterAttributes = partMetadata.GetValue<GenericParameterAttributes[]>(CompositionConstants.GenericParameterAttributesMetadataName); + + // if no constraints and attributes been specifed, anything can be created + if ((genericParameterConstraints == null) && (genericParameterAttributes == null)) + { + return true; + } + + if ((genericParameterConstraints != null) && (genericParameterConstraints.Length != partArity)) + { + return false; + } + + if ((genericParameterAttributes != null) && (genericParameterAttributes.Length != partArity)) + { + return false; + } + + for (int i = 0; i < partArity; i++) + { + if (!GenericServices.CanSpecialize( + specialization[i], + (genericParameterConstraints[i] as Type[]).CreateTypeSpecializations(specialization), + genericParameterAttributes[i])) + { + return false; + } + } + + return true; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/IReflectionPartCreationInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/IReflectionPartCreationInfo.cs new file mode 100644 index 00000000000..fa436109b91 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/IReflectionPartCreationInfo.cs @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Reflection; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal interface IReflectionPartCreationInfo : ICompositionElement + { + Type GetPartType(); + Lazy<Type> GetLazyPartType(); + ConstructorInfo GetConstructor(); + IDictionary<string, object> GetMetadata(); + IEnumerable<ExportDefinition> GetExports(); + IEnumerable<ImportDefinition> GetImports(); + bool IsDisposalRequired { get; } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportType.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportType.cs new file mode 100644 index 00000000000..7f085b919b5 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportType.cs @@ -0,0 +1,174 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Reflection; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + // Describes the import type of a Reflection-based import definition + internal class ImportType + { + private static readonly Type LazyOfTType = typeof(Lazy<>); + private static readonly Type LazyOfTMType = typeof(Lazy<,>); + private static readonly Type ExportFactoryOfTType = typeof(ExportFactory<>); + private static readonly Type ExportFactoryOfTMType = typeof(ExportFactory<,>); + + private readonly Type _type; + private readonly bool _isAssignableCollectionType; + private readonly Type _contractType; + private Func<Export, object> _castSingleValue; + private bool _isOpenGeneric = false; + + public ImportType(Type type, ImportCardinality cardinality) + { + Assumes.NotNull(type); + + this._type = type; + this._contractType = type; + + if (cardinality == ImportCardinality.ZeroOrMore) + { + this._isAssignableCollectionType = IsTypeAssignableCollectionType(type); + this._contractType = CheckForCollection(type); + } + + this._isOpenGeneric = type.ContainsGenericParameters; + this._contractType = CheckForLazyAndPartCreator(this._contractType); + } + + public bool IsAssignableCollectionType + { + get { return this._isAssignableCollectionType; } + } + + public Type ElementType { get; private set; } + + public Type ActualType + { + get { return this._type; } + } + + public bool IsPartCreator { get; private set; } + + public Type ContractType { get { return this._contractType; } } + + public Func<Export, object> CastExport + { + get + { + Assumes.IsTrue(!this._isOpenGeneric); + return this._castSingleValue; + } + } + + public Type MetadataViewType { get; private set; } + + private Type CheckForCollection(Type type) + { + this.ElementType = CollectionServices.GetEnumerableElementType(type); + if (this.ElementType != null) + { + return this.ElementType; + } + return type; + } + + private static bool IsGenericDescendentOf(Type type, Type baseGenericTypeDefinition) + { + if (type == typeof(object) || type == null) + { + return false; + } + + if (type.IsGenericType && type.GetGenericTypeDefinition() == baseGenericTypeDefinition) + { + return true; + } + + return IsGenericDescendentOf(type.BaseType, baseGenericTypeDefinition); + } + + + public static bool IsDescendentOf(Type type, Type baseType) + { + Assumes.NotNull(type); + Assumes.NotNull(baseType); + + if (!baseType.IsGenericTypeDefinition) + { + return baseType.IsAssignableFrom(type); + } + + return IsGenericDescendentOf(type, baseType.GetGenericTypeDefinition()); + } + + private Type CheckForLazyAndPartCreator(Type type) + { + if (type.IsGenericType) + { + Type genericType = type.GetGenericTypeDefinition().UnderlyingSystemType; + Type[] arguments = type.GetGenericArguments(); + + if (genericType == LazyOfTType) + { + if (!_isOpenGeneric) + { + this._castSingleValue = ExportServices.CreateStronglyTypedLazyFactory(arguments[0].UnderlyingSystemType, null); + } + return arguments[0]; + } + + if (genericType == LazyOfTMType) + { + this.MetadataViewType = arguments[1]; + if (!_isOpenGeneric) + { + this._castSingleValue = ExportServices.CreateStronglyTypedLazyFactory(arguments[0].UnderlyingSystemType, arguments[1].UnderlyingSystemType); + } + return arguments[0]; + } + + if(genericType != null && IsDescendentOf(genericType, ExportFactoryOfTType)) + { + this.IsPartCreator = true; + if (arguments.Length == 1) + { + if (!_isOpenGeneric) + { + this._castSingleValue = new ExportFactoryCreator(genericType).CreateStronglyTypedExportFactoryFactory(arguments[0].UnderlyingSystemType, null); + } + } + else if (arguments.Length == 2) + { + if (!_isOpenGeneric) + { + this._castSingleValue = new ExportFactoryCreator(genericType).CreateStronglyTypedExportFactoryFactory(arguments[0].UnderlyingSystemType, arguments[1].UnderlyingSystemType); + } + this.MetadataViewType = arguments[1]; + } + else + { + throw ExceptionBuilder.ExportFactory_TooManyGenericParameters(genericType.FullName); + } + return arguments[0]; + } + } + + return type; + } + + private static bool IsTypeAssignableCollectionType(Type type) + { + if (type.IsArray || CollectionServices.IsEnumerableOfT(type)) + { + return true; + } + + return false; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingItem.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingItem.cs new file mode 100644 index 00000000000..ca245fd315c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingItem.cs @@ -0,0 +1,115 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Globalization; +using System.Linq; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal abstract class ImportingItem + { + private readonly ContractBasedImportDefinition _definition; + private readonly ImportType _importType; + + protected ImportingItem(ContractBasedImportDefinition definition, ImportType importType) + { + Assumes.NotNull(definition); + + this._definition = definition; + this._importType = importType; + } + + public ContractBasedImportDefinition Definition + { + get { return this._definition; } + } + + public ImportType ImportType + { + get { return this._importType; } + } + + public object CastExportsToImportType(Export[] exports) + { + if (this.Definition.Cardinality == ImportCardinality.ZeroOrMore) + { + return CastExportsToCollectionImportType(exports); + } + else + { + return CastExportsToSingleImportType(exports); + } + } + + private object CastExportsToCollectionImportType(Export[] exports) + { + Assumes.NotNull(exports); + + // Element type could be null if the actually import type of the member is not a collection + // This particular case will end up failing when we set the member. + Type elementType = this.ImportType.ElementType ?? typeof(object); + + Array array = Array.CreateInstance(elementType, exports.Length); + + for (int i = 0; i < array.Length; i++) + { + object value = CastSingleExportToImportType(elementType, exports[i]); + + array.SetValue(value, i); + } + + return array; + } + + private object CastExportsToSingleImportType(Export[] exports) + { + Assumes.NotNull(exports); + Assumes.IsTrue(exports.Length < 2); + + if (exports.Length == 0) + { + return null; + } + + return CastSingleExportToImportType(this.ImportType.ActualType, exports[0]); + } + + private object CastSingleExportToImportType(Type type, Export export) + { + if (this.ImportType.CastExport != null) + { + return this.ImportType.CastExport(export); + } + + return Cast(type, export); + } + + private object Cast(Type type, Export export) + { + // TODO: Need to catch CompositionException to provide + // additional information about what member we're setting + // and the current dependency graph. + object value = export.Value; + + object result; + if (!ContractServices.TryCast(type, value, out result)) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportNotAssignableFromExport, + export.ToElement().DisplayName, + type.FullName), + this.Definition.ToElement()); + } + + return result; + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingMember.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingMember.cs new file mode 100644 index 00000000000..b6cd9712570 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingMember.cs @@ -0,0 +1,255 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ImportingMember : ImportingItem + { + private readonly ReflectionWritableMember _member; + + public ImportingMember(ContractBasedImportDefinition definition, ReflectionWritableMember member, ImportType importType) + : base(definition, importType) + { + Assumes.NotNull(definition, member); + + this._member = member; + } + + public void SetExportedValue(object instance, object value) + { + if (RequiresCollectionNormalization()) + { + this.SetCollectionMemberValue(instance, (IEnumerable)value); + } + else + { + this.SetSingleMemberValue(instance, value); + } + } + + private bool RequiresCollectionNormalization() + { + if (this.Definition.Cardinality != ImportCardinality.ZeroOrMore) + { // If we're not looking at a collection import, then don't + // 'normalize' the collection. + + return false; + } + + if (this._member.CanWrite && this.ImportType.IsAssignableCollectionType) + { // If we can simply replace the entire value of the property/field, then + // we don't need to 'normalize' the collection. + + return false; + } + + return true; + } + + private void SetSingleMemberValue(object instance, object value) + { + EnsureWritable(); + + try + { + this._member.SetValue(instance, value); + } + catch (TargetInvocationException exception) + { // Member threw an exception. Avoid letting this + // leak out as a 'raw' unhandled exception, instead, + // we'll add some context and rethrow. + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportThrewException, + this._member.GetDisplayName()), + Definition.ToElement(), + exception.InnerException); + } + catch (TargetParameterCountException exception) + { + // Exception was a TargetParameterCountException this occurs when we try to set an Indexer that has an Import + // this is not supported in MEF currently. Ideally we would validate against it, however, we already shipped + // so we will turn it into a ComposablePartException instead, that they should already be prepared for + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ImportNotValidOnIndexers, + this._member.GetDisplayName()), + Definition.ToElement(), + exception.InnerException); + } + } + + private void EnsureWritable() + { + if (!this._member.CanWrite) + { // Property does not have a setter, or + // field is marked as read-only. + + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportNotWritable, + this._member.GetDisplayName()), + Definition.ToElement()); + } + } + + private void SetCollectionMemberValue(object instance, IEnumerable values) + { + Assumes.NotNull(values); + + ICollection<object> collection = null; + Type itemType = CollectionServices.GetCollectionElementType(this.ImportType.ActualType); + if (itemType != null) + { + collection = GetNormalizedCollection(itemType, instance); + } + + EnsureCollectionIsWritable(collection); + PopulateCollection(collection, values); + } + + private ICollection<object> GetNormalizedCollection(Type itemType, object instance) + { + Assumes.NotNull(itemType); + + object collectionObject = null; + + if (this._member.CanRead) + { + try + { + collectionObject = this._member.GetValue(instance); + } + catch (TargetInvocationException exception) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionGetThrewException, + this._member.GetDisplayName()), + this.Definition.ToElement(), + exception.InnerException); + } + } + + if (collectionObject == null) + { + ConstructorInfo constructor = this.ImportType.ActualType.GetConstructor(Type.EmptyTypes); + + // If it contains a default public constructor create a new instance. + if (constructor != null) + { + try + { + collectionObject = constructor.SafeInvoke(); + } + catch (TargetInvocationException exception) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionConstructionThrewException, + this._member.GetDisplayName(), + this.ImportType.ActualType.FullName), + this.Definition.ToElement(), + exception.InnerException); + } + + SetSingleMemberValue(instance, collectionObject); + } + } + + if (collectionObject == null) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionNull, + this._member.GetDisplayName()), + this.Definition.ToElement()); + } + + return CollectionServices.GetCollectionWrapper(itemType, collectionObject); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void EnsureCollectionIsWritable(ICollection<object> collection) + { + bool isReadOnly = true; + + try + { + if (collection != null) + { + isReadOnly = collection.IsReadOnly; + } + } + catch (Exception exception) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionIsReadOnlyThrewException, + this._member.GetDisplayName(), + collection.GetType().FullName), + this.Definition.ToElement(), + exception); + } + + if (isReadOnly) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionNotWritable, + this._member.GetDisplayName()), + this.Definition.ToElement()); + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void PopulateCollection(ICollection<object> collection, IEnumerable values) + { + Assumes.NotNull(collection, values); + + try + { + collection.Clear(); + } + catch (Exception exception) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionClearThrewException, + this._member.GetDisplayName(), + collection.GetType().FullName), + this.Definition.ToElement(), + exception); + } + + foreach (object value in values) + { + try + { + collection.Add(value); + } + catch (Exception exception) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportCollectionAddThrewException, + this._member.GetDisplayName(), + collection.GetType().FullName), + this.Definition.ToElement(), + exception); + } + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingParameter.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingParameter.cs new file mode 100644 index 00000000000..0b1d15f3155 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ImportingParameter.cs @@ -0,0 +1,16 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ImportingParameter : ImportingItem + { + public ImportingParameter(ContractBasedImportDefinition definition, ImportType importType) + : base(definition, importType) + { + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs new file mode 100644 index 00000000000..a3802b9637d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/LazyMemberInfo.cs @@ -0,0 +1,207 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + public struct LazyMemberInfo + { + private readonly MemberTypes _memberType; + private MemberInfo[] _accessors; + private readonly Func<MemberInfo[]> _accessorsCreator; + + public LazyMemberInfo(MemberInfo member) + { + Requires.NotNull(member, "member"); + EnsureSupportedMemberType(member.MemberType, "member"); + + this._accessorsCreator = null; + this._memberType = member.MemberType; + + switch(this._memberType) + { + case MemberTypes.Property: + PropertyInfo property = (PropertyInfo)member; + Assumes.NotNull(property); + this._accessors = new MemberInfo[] { property.GetGetMethod(true), property.GetSetMethod(true) }; + break; + case MemberTypes.Event: + EventInfo event_ = (EventInfo)member; + this._accessors = new MemberInfo[] { event_.GetRaiseMethod(true), event_.GetAddMethod(true), event_.GetRemoveMethod(true) }; + break; + default: + this._accessors = new MemberInfo[] { member }; + break; + } + } + + public LazyMemberInfo(MemberTypes memberType, params MemberInfo[] accessors) + { + EnsureSupportedMemberType(memberType, "memberType"); + Requires.NotNull(accessors, "accessors"); + + string errorMessage; + if (!LazyMemberInfo.AreAccessorsValid(memberType, accessors, out errorMessage)) + { + throw new ArgumentException(errorMessage, "accessors"); + } + + this._memberType = memberType; + this._accessors = accessors; + this._accessorsCreator = null; + } + + public LazyMemberInfo(MemberTypes memberType, Func<MemberInfo[]> accessorsCreator) + { + EnsureSupportedMemberType(memberType, "memberType"); + Requires.NotNull(accessorsCreator, "accessorsCreator"); + + this._memberType = memberType; + this._accessors = null; + this._accessorsCreator = accessorsCreator; + } + + public MemberTypes MemberType + { + get { return this._memberType; } + } + + public MemberInfo[] GetAccessors() + { + if ((this._accessors == null) && (this._accessorsCreator != null)) + { + MemberInfo[] accessors = this._accessorsCreator.Invoke(); + + string errorMessage; + if (!LazyMemberInfo.AreAccessorsValid(this.MemberType, accessors, out errorMessage)) + { + throw new InvalidOperationException(errorMessage); + } + + this._accessors = accessors; + } + + return this._accessors; + } + + public override int GetHashCode() + { + if (this._accessorsCreator != null) + { + return this.MemberType.GetHashCode() ^ this._accessorsCreator.GetHashCode(); + } + else + { + Assumes.NotNull(this._accessors); + Assumes.NotNull(this._accessors[0]); + return this.MemberType.GetHashCode() ^ this._accessors[0].GetHashCode(); + } + } + + public override bool Equals(object obj) + { + LazyMemberInfo that = (LazyMemberInfo)obj; + + // Difefrent member types mean different members + if (this._memberType != that._memberType) + { + return false; + } + + // if any of the lazy memebers create accessors in a delay-loaded fashion, we simply compare the creators + if ((this._accessorsCreator != null) || (that._accessorsCreator != null)) + { + return object.Equals(this._accessorsCreator, that._accessorsCreator); + } + + // we are dealing with explicitly passed accessors in both cases + Assumes.NotNull(this._accessors); + Assumes.NotNull(that._accessors); + return this._accessors.SequenceEqual(that._accessors); + } + + public static bool operator ==(LazyMemberInfo left, LazyMemberInfo right) + { + return left.Equals(right); + } + + public static bool operator !=(LazyMemberInfo left, LazyMemberInfo right) + { + return !left.Equals(right); + } + + [ContractArgumentValidator] + private static void EnsureSupportedMemberType(MemberTypes memberType, string argument) + { + MemberTypes supportedTypes = MemberTypes.TypeInfo | MemberTypes.NestedType | MemberTypes.Constructor | MemberTypes.Field | MemberTypes.Method | MemberTypes.Property | MemberTypes.Event; + Requires.IsInMembertypeSet(memberType, argument, supportedTypes); + } + + private static bool AreAccessorsValid(MemberTypes memberType, MemberInfo[] accessors, out string errorMessage) + { + errorMessage = string.Empty; + if (accessors == null) + { + errorMessage = Strings.LazyMemberInfo_AccessorsNull; + return false; + } + + if (accessors.All(accessor => accessor == null)) + { + errorMessage = Strings.LazyMemberInfo_NoAccessors; + return false; + } + + switch (memberType) + { + case MemberTypes.Property: + if (accessors.Length != 2) + { + errorMessage = Strings.LazyMemberInfo_InvalidPropertyAccessors_Cardinality; + return false; + } + + if (accessors.Where(accessor => (accessor != null) && (accessor.MemberType != MemberTypes.Method)).Any()) + { + errorMessage = Strings.LazyMemberinfo_InvalidPropertyAccessors_AccessorType; + return false; + } + + break; + + case MemberTypes.Event: + if (accessors.Length != 3) + { + errorMessage = Strings.LazyMemberInfo_InvalidEventAccessors_Cardinality; + return false; + } + + if (accessors.Where(accessor => (accessor != null) && (accessor.MemberType != MemberTypes.Method)).Any()) + { + errorMessage = Strings.LazyMemberinfo_InvalidEventAccessors_AccessorType; + return false; + } + + break; + + default: + if ( + (accessors.Length != 1) || + ((accessors.Length == 1) && (accessors[0].MemberType != memberType))) + { + errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.LazyMemberInfo_InvalidAccessorOnSimpleMember, memberType); + return false; + } + + break; + } + return true; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorExportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorExportDefinition.cs new file mode 100644 index 00000000000..517dd59da1a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorExportDefinition.cs @@ -0,0 +1,62 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class PartCreatorExportDefinition : ExportDefinition + { + private readonly ExportDefinition _productDefinition; + private IDictionary<string, object> _metadata; + + public PartCreatorExportDefinition(ExportDefinition productDefinition) + : base() + { + this._productDefinition = productDefinition; + } + + public override string ContractName + { + get + { + return CompositionConstants.PartCreatorContractName; + } + } + + public override IDictionary<string, object> Metadata + { + get + { + if (this._metadata == null) + { + var metadata = new Dictionary<string, object>(this._productDefinition.Metadata); + metadata[CompositionConstants.ExportTypeIdentityMetadataName] = CompositionConstants.PartCreatorTypeIdentity; + metadata[CompositionConstants.ProductDefinitionMetadataName] = this._productDefinition; + + this._metadata = metadata.AsReadOnly(); + } + return this._metadata; + } + } + + internal static bool IsProductConstraintSatisfiedBy(ImportDefinition productImportDefinition, ExportDefinition exportDefinition) + { + object productValue = null; + if (exportDefinition.Metadata.TryGetValue(CompositionConstants.ProductDefinitionMetadataName, out productValue)) + { + ExportDefinition productDefinition = productValue as ExportDefinition; + + if (productDefinition != null) + { + return productImportDefinition.IsConstraintSatisfiedBy(productDefinition); + } + } + + return false; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorMemberImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorMemberImportDefinition.cs new file mode 100644 index 00000000000..e98d7446bcd --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorMemberImportDefinition.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class PartCreatorMemberImportDefinition : ReflectionMemberImportDefinition, IPartCreatorImportDefinition + { + private readonly ContractBasedImportDefinition _productImportDefinition; + + public PartCreatorMemberImportDefinition( + LazyMemberInfo importingLazyMember, + ICompositionElement origin, + ContractBasedImportDefinition productImportDefinition) + : base(importingLazyMember, CompositionConstants.PartCreatorContractName, CompositionConstants.PartCreatorTypeIdentity, + productImportDefinition.RequiredMetadata, productImportDefinition.Cardinality, productImportDefinition.IsRecomposable, false, productImportDefinition.RequiredCreationPolicy, MetadataServices.EmptyMetadata, origin) + { + Assumes.NotNull(productImportDefinition); + this._productImportDefinition = productImportDefinition; + } + + public ContractBasedImportDefinition ProductImportDefinition { get { return this._productImportDefinition; } } + + [SuppressMessage("Microsoft.Contracts", "CC1055", Justification = "Precondition is being validated in the call to base")] + public override bool IsConstraintSatisfiedBy(ExportDefinition exportDefinition) + { + if (!base.IsConstraintSatisfiedBy(exportDefinition)) + { + return false; + } + + return PartCreatorExportDefinition.IsProductConstraintSatisfiedBy(this._productImportDefinition, exportDefinition); + } + + public override Expression<Func<ExportDefinition, bool>> Constraint + { + get + { + return ConstraintServices.CreatePartCreatorConstraint(base.Constraint, this._productImportDefinition); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorParameterImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorParameterImportDefinition.cs new file mode 100644 index 00000000000..79aeb0c186a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/PartCreatorParameterImportDefinition.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class PartCreatorParameterImportDefinition : ReflectionParameterImportDefinition, IPartCreatorImportDefinition + { + private readonly ContractBasedImportDefinition _productImportDefinition; + + public PartCreatorParameterImportDefinition( + Lazy<ParameterInfo> importingLazyParameter, + ICompositionElement origin, + ContractBasedImportDefinition productImportDefinition) + : base(importingLazyParameter, CompositionConstants.PartCreatorContractName, CompositionConstants.PartCreatorTypeIdentity, + productImportDefinition.RequiredMetadata, productImportDefinition.Cardinality, CreationPolicy.Any, MetadataServices.EmptyMetadata, origin) + { + Assumes.NotNull(productImportDefinition); + this._productImportDefinition = productImportDefinition; + } + + public ContractBasedImportDefinition ProductImportDefinition { get { return this._productImportDefinition; } } + + [SuppressMessage("Microsoft.Contracts", "CC1055", Justification = "Precondition is being validated in the call to base")] + public override bool IsConstraintSatisfiedBy(ExportDefinition exportDefinition) + { + if (!base.IsConstraintSatisfiedBy(exportDefinition)) + { + return false; + } + return PartCreatorExportDefinition.IsProductConstraintSatisfiedBy(this._productImportDefinition, exportDefinition); + } + + public override Expression<Func<ExportDefinition, bool>> Constraint + { + get + { + return ConstraintServices.CreatePartCreatorConstraint(base.Constraint, this._productImportDefinition); + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionComposablePart.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionComposablePart.cs new file mode 100644 index 00000000000..72e8207b1db --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionComposablePart.cs @@ -0,0 +1,582 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + // This + internal class ReflectionComposablePart : ComposablePart, ICompositionElement + { + private readonly ReflectionComposablePartDefinition _definition; + private readonly Dictionary<ImportDefinition, object> _importValues = new Dictionary<ImportDefinition, object>(); + private readonly Dictionary<ImportDefinition, ImportingItem> _importsCache = new Dictionary<ImportDefinition, ImportingItem>(); + private readonly Dictionary<int, ExportingMember> _exportsCache = new Dictionary<int, ExportingMember>(); + private bool _invokeImportsSatisfied = true; + private bool _invokingImportsSatisfied = false; + private bool _initialCompositionComplete = false; + private volatile object _cachedInstance; + private object _lock = new object(); + + public ReflectionComposablePart(ReflectionComposablePartDefinition definition) + { + Requires.NotNull(definition, "definition"); + + this._definition = definition; + } + + public ReflectionComposablePart(ReflectionComposablePartDefinition definition, object attributedPart) + { + Requires.NotNull(definition, "definition"); + Requires.NotNull(attributedPart, "attributedPart"); + + this._definition = definition; + + if (attributedPart is ValueType) + { + throw new ArgumentException(Strings.ArgumentValueType, "attributedPart"); + } + this._cachedInstance = attributedPart; + } + + protected virtual void EnsureRunning() + { + } + + [ContractArgumentValidator] + [SuppressMessage("Microsoft.Contracts", "CC1053")] + protected void RequiresRunning() + { + this.EnsureRunning(); + } + + protected virtual void ReleaseInstanceIfNecessary(object instance) + { + } + + protected object CachedInstance + { + get + { + lock (this._lock) + { + return this._cachedInstance; + } + } + } + + public ReflectionComposablePartDefinition Definition + { + get + { + this.RequiresRunning(); + return this._definition; + } + } + + public override IDictionary<string, object> Metadata + { + get + { + this.RequiresRunning(); + return this.Definition.Metadata; + } + } + + public sealed override IEnumerable<ImportDefinition> ImportDefinitions + { + get + { + this.RequiresRunning(); + return this.Definition.ImportDefinitions; + } + } + + public sealed override IEnumerable<ExportDefinition> ExportDefinitions + { + get + { + this.RequiresRunning(); + return this.Definition.ExportDefinitions; + } + } + + string ICompositionElement.DisplayName + { + get { return GetDisplayName(); } + } + + ICompositionElement ICompositionElement.Origin + { + get { return Definition; } + } + + // This is the ONLY method which is not executed under the ImportEngine composition lock. + // We need to protect all state that is accesses + public override object GetExportedValue(ExportDefinition definition) + { + this.RequiresRunning(); + // given the implementation of the ImportEngine, this iwll be called under a lock if the part is still being composed + // This is only called outside of the lock when the part is fully composed + // based on that we only protect: + // _exportsCache - and thus all calls to GetExportingMemberFromDefinition + // access to _importValues + // access to _initialCompositionComplete + // access to _instance + Requires.NotNull(definition, "definition"); + + ExportingMember member = null; + lock (this._lock) + { + member = GetExportingMemberFromDefinition(definition); + if (member == null) + { + throw ExceptionBuilder.CreateExportDefinitionNotOnThisComposablePart("definition"); + } + this.EnsureGettable(); + } + + return this.GetExportedValue(member); + } + + public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports) + { + this.RequiresRunning(); + Requires.NotNull(definition, "definition"); + Requires.NotNull(exports, "exports");; + + ImportingItem item = GetImportingItemFromDefinition(definition); + if (item == null) + { + throw ExceptionBuilder.CreateImportDefinitionNotOnThisComposablePart("definition"); + } + + EnsureSettable(definition); + + // Avoid walking over exports many times + Export[] exportsAsArray = exports.AsArray(); + EnsureCardinality(definition, exportsAsArray); + + SetImport(item, exportsAsArray); + } + + public override void Activate() + { + this.RequiresRunning(); + + this.SetNonPrerequisiteImports(); + + // Whenever we are composed/recomposed notify the instance + this.NotifyImportSatisfied(); + + lock (this._lock) + { + this._initialCompositionComplete = true; + } + } + + public override string ToString() + { + return this.GetDisplayName(); + } + + private object GetExportedValue(ExportingMember member) + { + object instance = null; + if (member.RequiresInstance) + { // Only activate the instance if we actually need to + + instance = this.GetInstanceActivatingIfNeeded(); + } + + return member.GetExportedValue(instance, this._lock); + } + + private void SetImport(ImportingItem item, Export[] exports) + { + object value = item.CastExportsToImportType(exports); + + lock (this._lock) + { + this._invokeImportsSatisfied = true; + this._importValues[item.Definition] = value; + } + } + + private object GetInstanceActivatingIfNeeded() + { + if (this._cachedInstance != null) + { + return this._cachedInstance; + } + else + { + ConstructorInfo constructor = null; + object[] arguments = null; + // determine whether activation is required, and collect necessary information for activation + // we need to do that under a lock + lock (this._lock) + { + if (!this.RequiresActivation()) + { + return null; + } + + constructor = this.Definition.GetConstructor(); + if (constructor == null) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_PartConstructorMissing, + this.Definition.GetPartType().FullName), + this.Definition.ToElement()); + } + arguments = this.GetConstructorArguments(); + } + + // create instance outside of the lock + object createdInstance = this.CreateInstance(constructor, arguments); + + SetPrerequisiteImports(); + + // set the created instance + lock (this._lock) + { + if (this._cachedInstance == null) + { + this._cachedInstance = createdInstance; + createdInstance = null; + } + } + + // if the instance has been already set + if (createdInstance == null) + { + this.ReleaseInstanceIfNecessary(createdInstance); + } + } + + return this._cachedInstance; + } + + private object[] GetConstructorArguments() + { + ReflectionParameterImportDefinition[] parameterImports = this.ImportDefinitions.OfType<ReflectionParameterImportDefinition>().ToArray(); + object[] arguments = new object[parameterImports.Length]; + + this.UseImportedValues( + parameterImports, + (import, definition, value) => + { + if (definition.Cardinality == ImportCardinality.ZeroOrMore && !import.ImportType.IsAssignableCollectionType) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_ImportManyOnParameterCanOnlyBeAssigned, + this.Definition.GetPartType().FullName, + definition.ImportingLazyParameter.Value.Name), + this.Definition.ToElement()); + } + + arguments[definition.ImportingLazyParameter.Value.Position] = value; + }, + true); + + return arguments; + } + + // alwayc called under a lock + private bool RequiresActivation() + { + // If we have any imports then we need activation + // (static imports are not supported) + if (this.ImportDefinitions.Any()) + { + return true; + } + + // If we have any instance exports, then we also + // need activation. + return this.ExportDefinitions.Any(definition => + { + ExportingMember member = GetExportingMemberFromDefinition(definition); + + return member.RequiresInstance; + }); + } + + // this is called under a lock + private void EnsureGettable() + { + // If we're already composed then we know that + // all pre-req imports have been satisfied + if (_initialCompositionComplete) + { + return; + } + + // Make sure all pre-req imports have been set + foreach (ImportDefinition definition in ImportDefinitions.Where(definition => definition.IsPrerequisite)) + { + if (!this._importValues.ContainsKey(definition)) + { + throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, + Strings.InvalidOperation_GetExportedValueBeforePrereqImportSet, + definition.ToElement().DisplayName)); + } + } + } + + private void EnsureSettable(ImportDefinition definition) + { + lock (this._lock) + { + if (this._initialCompositionComplete && !definition.IsRecomposable) + { + throw new InvalidOperationException(Strings.InvalidOperation_DefinitionCannotBeRecomposed); + } + } + } + + private static void EnsureCardinality(ImportDefinition definition, Export[] exports) + { + Requires.NullOrNotNullElements(exports, "exports"); + + ExportCardinalityCheckResult result = ExportServices.CheckCardinality(definition, exports); + + switch (result) + { + case ExportCardinalityCheckResult.NoExports: + throw new ArgumentException(Strings.Argument_ExportsEmpty, "exports"); + + case ExportCardinalityCheckResult.TooManyExports: + throw new ArgumentException(Strings.Argument_ExportsTooMany, "exports"); + + default: + Assumes.IsTrue(result == ExportCardinalityCheckResult.Match); + break; + } + } + + private object CreateInstance(ConstructorInfo constructor, object[] arguments) + { + Exception exception = null; + object instance = null; + + try + { + instance = constructor.SafeInvoke(arguments); + } + catch (TypeInitializationException ex) + { + exception = ex; + } + catch (TargetInvocationException ex) + { + exception = ex.InnerException; + } + + if (exception != null) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_PartConstructorThrewException, + Definition.GetPartType().FullName), + Definition.ToElement(), + exception); + } + + return instance; + } + + private void SetNonPrerequisiteImports() + { + IEnumerable<ImportDefinition> members = this.ImportDefinitions.Where(import => !import.IsPrerequisite); + + // NOTE: Dev10 484204 The validation is turned off for post imports because of it broke declarative composition + this.UseImportedValues(members, SetExportedValueForImport, false); + } + + private void SetPrerequisiteImports() + { + IEnumerable<ImportDefinition> members = this.ImportDefinitions.Where(import => import.IsPrerequisite); + + // NOTE: Dev10 484204 The validation is turned off for post imports because of it broke declarative composition + this.UseImportedValues(members, SetExportedValueForImport, false); + } + + private void SetExportedValueForImport(ImportingItem import, ImportDefinition definition, object value) + { + ImportingMember importMember = (ImportingMember)import; + + object instance = this.GetInstanceActivatingIfNeeded(); + + importMember.SetExportedValue(instance, value); + } + + private void UseImportedValues<TImportDefinition>(IEnumerable<TImportDefinition> definitions, Action<ImportingItem, TImportDefinition, object> useImportValue, bool errorIfMissing) + where TImportDefinition : ImportDefinition + { + var result = CompositionResult.SucceededResult; + + foreach (var definition in definitions) + { + ImportingItem import = GetImportingItemFromDefinition(definition); + + object value; + if (!TryGetImportValue(definition, out value)) + { + if (!errorIfMissing) + { + continue; + } + + if (definition.Cardinality == ImportCardinality.ExactlyOne) + { + var error = CompositionError.Create( + CompositionErrorId.ImportNotSetOnPart, + Strings.ImportNotSetOnPart, + this.Definition.GetPartType().FullName, + definition.ToString()); + result = result.MergeError(error); + continue; + } + else + { + value = import.CastExportsToImportType(new Export[0]); + } + } + + useImportValue(import, definition, value); + } + + result.ThrowOnErrors(); + } + + private bool TryGetImportValue(ImportDefinition definition, out object value) + { + lock (this._lock) + { + if (this._importValues.TryGetValue(definition, out value)) + { + this._importValues.Remove(definition); + return true; + } + } + + value = null; + return false; + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void NotifyImportSatisfied() + { + if (this._invokeImportsSatisfied && !this._invokingImportsSatisfied) + { + IPartImportsSatisfiedNotification notify = this.GetInstanceActivatingIfNeeded() as IPartImportsSatisfiedNotification; + if (notify != null) + { + try + { + // Reentrancy on composition notifications is allowed, so set this first to avoid + // an infinte loop of notifications. + this._invokingImportsSatisfied = true; + + notify.OnImportsSatisfied(); + } + catch (Exception exception) + { + throw new ComposablePartException( + String.Format(CultureInfo.CurrentCulture, + Strings.ReflectionModel_PartOnImportsSatisfiedThrewException, + Definition.GetPartType().FullName), + Definition.ToElement(), + exception); + } + finally + { + this._invokingImportsSatisfied = false; + } + + this._invokeImportsSatisfied = false; + } + } + } + + // this is always called under a lock + private ExportingMember GetExportingMemberFromDefinition(ExportDefinition definition) + { + ExportingMember result; + ReflectionMemberExportDefinition reflectionExport = definition as ReflectionMemberExportDefinition; + if (reflectionExport == null) + { + return null; + } + + int exportIndex = reflectionExport.GetIndex(); + if (!_exportsCache.TryGetValue(exportIndex, out result)) + { + result = GetExportingMember(definition); + if (result != null) + { + _exportsCache[exportIndex] = result; + } + } + + return result; + } + + private ImportingItem GetImportingItemFromDefinition(ImportDefinition definition) + { + ImportingItem result; + if (!_importsCache.TryGetValue(definition, out result)) + { + result = GetImportingItem(definition); + if (result != null) + { + _importsCache[definition] = result; + } + } + + return result; + } + + private static ImportingItem GetImportingItem(ImportDefinition definition) + { + ReflectionImportDefinition reflectionDefinition = definition as ReflectionImportDefinition; + if (reflectionDefinition != null) + { + return reflectionDefinition.ToImportingItem(); + } + + // Don't recognize it + return null; + } + + private static ExportingMember GetExportingMember(ExportDefinition definition) + { + ReflectionMemberExportDefinition exportDefinition = definition as ReflectionMemberExportDefinition; + if (exportDefinition != null) + { + return exportDefinition.ToExportingMember(); + } + + // Don't recognize it + return null; + } + + private string GetDisplayName() + { + return this._definition.GetPartType().GetDisplayName(); + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionComposablePartDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionComposablePartDefinition.cs new file mode 100644 index 00000000000..010a7329ec8 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionComposablePartDefinition.cs @@ -0,0 +1,262 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.ComponentModel.Composition.Hosting; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionComposablePartDefinition : ComposablePartDefinition, ICompositionElement + { + private readonly IReflectionPartCreationInfo _creationInfo; + + private volatile IEnumerable<ImportDefinition> _imports; + private volatile IEnumerable<ExportDefinition> _exports; + private volatile IDictionary<string, object> _metadata; + private volatile ConstructorInfo _constructor; + private object _lock = new object(); + + public ReflectionComposablePartDefinition(IReflectionPartCreationInfo creationInfo) + { + Assumes.NotNull(creationInfo); + this._creationInfo = creationInfo; + } + + public Type GetPartType() + { + return this._creationInfo.GetPartType(); + } + + public Lazy<Type> GetLazyPartType() + { + return this._creationInfo.GetLazyPartType(); + } + + public ConstructorInfo GetConstructor() + { + if (this._constructor == null) + { + ConstructorInfo constructor = this._creationInfo.GetConstructor(); + lock (this._lock) + { + if (this._constructor == null) + { + this._constructor = constructor; + } + } + } + + return this._constructor; + } + + public override IEnumerable<ExportDefinition> ExportDefinitions + { + get + { + if (this._exports == null) + { + ExportDefinition[] exports = this._creationInfo.GetExports().ToArray(); + lock (this._lock) + { + if (this._exports == null) + { + this._exports = exports; + } + } + } + return this._exports; + } + } + + public override IEnumerable<ImportDefinition> ImportDefinitions + { + get + { + if (this._imports == null) + { + ImportDefinition[] imports = this._creationInfo.GetImports().ToArray(); + lock (this._lock) + { + if (this._imports == null) + { + this._imports = imports; + } + } + } + return this._imports; + } + } + + public override IDictionary<string, object> Metadata + { + get + { + if (this._metadata == null) + { + IDictionary<string, object> metadata = this._creationInfo.GetMetadata().AsReadOnly(); + lock (this._lock) + { + if (this._metadata == null) + { + this._metadata = metadata; + } + } + } + return this._metadata; + } + } + + internal bool IsDisposalRequired + { + get + { + return this._creationInfo.IsDisposalRequired; + } + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + public override ComposablePart CreatePart() + { + if (this.IsDisposalRequired) + { + return new DisposableReflectionComposablePart(this); + } + else + { + return new ReflectionComposablePart(this); + } + } + + internal override ComposablePartDefinition GetGenericPartDefinition() + { + GenericSpecializationPartCreationInfo genericCreationInfo = this._creationInfo as GenericSpecializationPartCreationInfo; + if (genericCreationInfo != null) + { + return genericCreationInfo.OriginalPart; + } + + return null; + } + + internal override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition) + { + if (this.IsGeneric()) + { + List<Tuple<ComposablePartDefinition, ExportDefinition>> exports = null; + + var genericParameters = (definition.Metadata.Count > 0) ? definition.Metadata.GetValue<IEnumerable<object>>(CompositionConstants.GenericParametersMetadataName) : null; + // if and only if generic parameters have been supplied can we attempt to "close" the generic + if (genericParameters != null) + { + Type[] genericTypeParameters = null; + // we only undestand types + if (TryGetGenericTypeParameters(genericParameters, out genericTypeParameters)) + { + // go through all orders of generic parameters that part exports allows + foreach (Type[] candidateParameters in this.GetCandidateParameters(genericTypeParameters)) + { + ComposablePartDefinition candidatePart = null; + if (this.TryMakeGenericPartDefinition(candidateParameters, out candidatePart)) + { + var candidatePartExports = candidatePart.GetExports(definition); + if (candidatePartExports != ComposablePartDefinition._EmptyExports) + { + exports = exports.FastAppendToListAllowNulls(candidatePartExports); + } + } + } + } + } + return exports ?? _EmptyExports; + } + else + { + return base.GetExports(definition); + } + } + + private IEnumerable<Type[]> GetCandidateParameters(Type[] genericParameters) + { + // we iterate over all exports and find only generic ones. Assuming the arity matches, we reorder the original parameters + foreach (ExportDefinition export in this.ExportDefinitions) + { + var genericParametersOrder = export.Metadata.GetValue<int[]>(CompositionConstants.GenericExportParametersOrderMetadataName); + if ((genericParametersOrder != null) && (genericParametersOrder.Length == genericParameters.Length)) + { + yield return GenericServices.Reorder(genericParameters, genericParametersOrder); + } + } + } + + private static bool TryGetGenericTypeParameters(IEnumerable<object> genericParameters, out Type[] genericTypeParameters) + { + genericTypeParameters = genericParameters as Type[]; + if (genericTypeParameters == null) + { + object[] genericParametersAsArray = genericParameters.AsArray(); + genericTypeParameters = new Type[genericParametersAsArray.Length]; + for (int i = 0; i < genericParametersAsArray.Length; i++) + { + genericTypeParameters[i] = genericParametersAsArray[i] as Type; + if (genericTypeParameters[i] == null) + { + return false; + } + } + } + return true; + } + + internal bool TryMakeGenericPartDefinition(Type[] genericTypeParameters, out ComposablePartDefinition genericPartDefinition) + { + genericPartDefinition = null; + + if (!GenericSpecializationPartCreationInfo.CanSpecialize(this.Metadata, genericTypeParameters)) + { + return false; + } + + genericPartDefinition = new ReflectionComposablePartDefinition(new GenericSpecializationPartCreationInfo(this._creationInfo, this, genericTypeParameters)); + return true; + } + + string ICompositionElement.DisplayName + { + get { return this._creationInfo.DisplayName; } + } + + ICompositionElement ICompositionElement.Origin + { + get { return this._creationInfo.Origin; } + } + + public override string ToString() + { + return this._creationInfo.DisplayName; + } + + public override bool Equals(object obj) + { + ReflectionComposablePartDefinition that = obj as ReflectionComposablePartDefinition; + if (that == null) + { + return false; + } + + return this._creationInfo.Equals(that._creationInfo); + } + + public override int GetHashCode() + { + return this._creationInfo.GetHashCode(); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionExtensions.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionExtensions.cs new file mode 100644 index 00000000000..a5ac1bccf4a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionExtensions.cs @@ -0,0 +1,116 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; +using System.Collections.Generic; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal static class ReflectionExtensions + { + public static ReflectionMember ToReflectionMember(this LazyMemberInfo lazyMember) + { + MemberInfo[] accessors = lazyMember.GetAccessors(); + MemberTypes memberType = lazyMember.MemberType; + + switch (memberType) + { + case MemberTypes.Field: + Assumes.IsTrue(accessors.Length == 1); + return ((FieldInfo)accessors[0]).ToReflectionField(); + + case MemberTypes.Property: + Assumes.IsTrue(accessors.Length == 2); + return ReflectionExtensions.CreateReflectionProperty((MethodInfo)accessors[0], (MethodInfo)accessors[1]); + + case MemberTypes.NestedType: + case MemberTypes.TypeInfo: + return ((Type)accessors[0]).ToReflectionType(); + + default: + Assumes.IsTrue(memberType == MemberTypes.Method); + return ((MethodInfo)accessors[0]).ToReflectionMethod(); + } + } + + public static LazyMemberInfo ToLazyMember(this MemberInfo member) + { + Assumes.NotNull(member); + + if (member.MemberType == MemberTypes.Property) + { + PropertyInfo property = member as PropertyInfo; + Assumes.NotNull(property); + + MemberInfo[] accessors = new MemberInfo[] { property.GetGetMethod(true), property.GetSetMethod(true)}; + return new LazyMemberInfo(MemberTypes.Property, accessors); + } + else + { + return new LazyMemberInfo(member); + } + } + + public static ReflectionWritableMember ToReflectionWriteableMember(this LazyMemberInfo lazyMember) + { + Assumes.IsTrue((lazyMember.MemberType == MemberTypes.Field) || (lazyMember.MemberType == MemberTypes.Property)); + + ReflectionWritableMember reflectionMember = lazyMember.ToReflectionMember() as ReflectionWritableMember; + Assumes.NotNull(reflectionMember); + + return reflectionMember; + } + + + public static ReflectionProperty ToReflectionProperty(this PropertyInfo property) + { + Assumes.NotNull(property); + return CreateReflectionProperty(property.GetGetMethod(true), property.GetSetMethod(true)); + } + + public static ReflectionProperty CreateReflectionProperty(MethodInfo getMethod, MethodInfo setMethod) + { + Assumes.IsTrue(getMethod != null || setMethod != null); + + return new ReflectionProperty(getMethod, setMethod); + } + + public static ReflectionParameter ToReflectionParameter(this ParameterInfo parameter) + { + Assumes.NotNull(parameter); + return new ReflectionParameter(parameter); + } + + public static ReflectionMethod ToReflectionMethod(this MethodInfo method) + { + Assumes.NotNull(method); + return new ReflectionMethod(method); + } + + public static ReflectionField ToReflectionField(this FieldInfo field) + { + Assumes.NotNull(field); + return new ReflectionField(field); + } + + public static ReflectionType ToReflectionType(this Type type) + { + Assumes.NotNull(type); + return new ReflectionType(type); + } + + public static ReflectionWritableMember ToReflectionWritableMember(this MemberInfo member) + { + Assumes.NotNull(member); + if (member.MemberType == MemberTypes.Property) + { + return ((PropertyInfo)member).ToReflectionProperty(); + } + + return ((FieldInfo)member).ToReflectionField(); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionField.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionField.cs new file mode 100644 index 00000000000..1cac368742c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionField.cs @@ -0,0 +1,67 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionField : ReflectionWritableMember + { + private readonly FieldInfo _field; + + public ReflectionField(FieldInfo field) + { + Assumes.NotNull(field); + + this._field = field; + } + + public FieldInfo UndelyingField + { + get { return this._field; } + } + + public override MemberInfo UnderlyingMember + { + get { return this.UndelyingField; } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanWrite + { + get { return !this.UndelyingField.IsInitOnly; } + } + + public override bool RequiresInstance + { + get { return !this.UndelyingField.IsStatic; } + } + + public override Type ReturnType + { + get { return this.UndelyingField.FieldType; } + } + + public override ReflectionItemType ItemType + { + get { return ReflectionItemType.Field; } + } + + public override object GetValue(object instance) + { + return this.UndelyingField.SafeGetValue(instance); + } + + public override void SetValue(object instance, object value) + { + this.UndelyingField.SafeSetValue(instance, value); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionImportDefinition.cs new file mode 100644 index 00000000000..cda7f726801 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionImportDefinition.cs @@ -0,0 +1,48 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal abstract class ReflectionImportDefinition : ContractBasedImportDefinition, ICompositionElement + { + private readonly ICompositionElement _origin; + + public ReflectionImportDefinition( + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + bool isRecomposable, + bool isPrerequisite, + CreationPolicy requiredCreationPolicy, + IDictionary<string, object> metadata, + ICompositionElement origin) + : base(contractName, requiredTypeIdentity, requiredMetadata, cardinality, isRecomposable, isPrerequisite, requiredCreationPolicy, metadata) + { + this._origin = origin; + } + + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + ICompositionElement ICompositionElement.Origin + { + get { return this._origin; } + } + + public abstract ImportingItem ToImportingItem(); + + protected abstract string GetDisplayName(); + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionItem.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionItem.cs new file mode 100644 index 00000000000..3d649af1e0c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionItem.cs @@ -0,0 +1,16 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Reflection; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal abstract class ReflectionItem + { + public abstract string Name { get; } + public abstract string GetDisplayName(); + public abstract Type ReturnType { get; } + public abstract ReflectionItemType ItemType { get; } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionItemType.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionItemType.cs new file mode 100644 index 00000000000..2e7eaf4eba4 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionItemType.cs @@ -0,0 +1,16 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal enum ReflectionItemType : int + { + Parameter = 0, + Field = 1, + Property = 2, + Method = 3, + Type = 4, + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMember.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMember.cs new file mode 100644 index 00000000000..c34abc5b56a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMember.cs @@ -0,0 +1,42 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal abstract class ReflectionMember : ReflectionItem + { + public abstract bool CanRead + { + get; + } + + public Type DeclaringType + { + get { return this.UnderlyingMember.DeclaringType; } + } + + public override string Name + { + get { return this.UnderlyingMember.Name; } + } + + public override string GetDisplayName() + { + return this.UnderlyingMember.GetDisplayName(); + } + + public abstract bool RequiresInstance + { + get; + } + + public abstract MemberInfo UnderlyingMember { get; } + + public abstract object GetValue(object instance); + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMemberExportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMemberExportDefinition.cs new file mode 100644 index 00000000000..04e51d64953 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMemberExportDefinition.cs @@ -0,0 +1,93 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionMemberExportDefinition : ExportDefinition, ICompositionElement + { + private readonly LazyMemberInfo _member; + private readonly ExportDefinition _exportDefinition; + private readonly ICompositionElement _origin; + private IDictionary<string, object> _metadata; + + public ReflectionMemberExportDefinition(LazyMemberInfo member, ExportDefinition exportDefinition, ICompositionElement origin) + { + Assumes.NotNull(exportDefinition); + + this._member = member; + this._exportDefinition = exportDefinition; + this._origin = origin; + } + + public override string ContractName + { + get { return this._exportDefinition.ContractName; } + } + + public LazyMemberInfo ExportingLazyMember + { + get { return this._member; } + } + + public override IDictionary<string, object> Metadata + { + get + { + if (this._metadata == null) + { + this._metadata = this._exportDefinition.Metadata.AsReadOnly(); + } + return this._metadata; + } + } + + string ICompositionElement.DisplayName + { + get { return this.GetDisplayName(); } + } + + ICompositionElement ICompositionElement.Origin + { + get { return this._origin; } + } + + public override string ToString() + { + return this.GetDisplayName(); + } + + public int GetIndex() + { + return this.ExportingLazyMember.ToReflectionMember().UnderlyingMember.MetadataToken; + } + + public ExportingMember ToExportingMember() + { + return new ExportingMember(this, this.ToReflectionMember()); + } + + private ReflectionMember ToReflectionMember() + { + return this.ExportingLazyMember.ToReflectionMember(); + } + + private string GetDisplayName() + { + return string.Format(CultureInfo.CurrentCulture, + "{0} (ContractName=\"{1}\")", // NOLOC + this.ToReflectionMember().GetDisplayName(), + this.ContractName); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMemberImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMemberImportDefinition.cs new file mode 100644 index 00000000000..9d958ae46ac --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMemberImportDefinition.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using Microsoft.Internal.Collections; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionMemberImportDefinition : ReflectionImportDefinition + { + private LazyMemberInfo _importingLazyMember; + + public ReflectionMemberImportDefinition( + LazyMemberInfo importingLazyMember, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + bool isRecomposable, + bool isPrerequisite, + CreationPolicy requiredCreationPolicy, + IDictionary<string, object> metadata, + ICompositionElement origin) + : base(contractName, requiredTypeIdentity, requiredMetadata, cardinality, isRecomposable, isPrerequisite, requiredCreationPolicy, metadata, origin) + { + Assumes.NotNull(contractName); + + this._importingLazyMember = importingLazyMember; + } + + public override ImportingItem ToImportingItem() + { + ReflectionWritableMember member = this.ImportingLazyMember.ToReflectionWriteableMember(); + return new ImportingMember(this, member, new ImportType(member.ReturnType, this.Cardinality)); + } + + public LazyMemberInfo ImportingLazyMember + { + get { return this._importingLazyMember; } + } + + protected override string GetDisplayName() + { + return string.Format( + CultureInfo.CurrentCulture, + "{0} (ContractName=\"{1}\")", // NOLOC + this.ImportingLazyMember.ToReflectionMember().GetDisplayName(), + this.ContractName); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMethod.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMethod.cs new file mode 100644 index 00000000000..8ed39392c61 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionMethod.cs @@ -0,0 +1,71 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.Hosting; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; +using System.ComponentModel.Composition.Primitives; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal partial class ReflectionMethod : ReflectionMember + { + private readonly MethodInfo _method; + + public ReflectionMethod(MethodInfo method) + { + Assumes.NotNull(method); + + this._method = method; + } + + public MethodInfo UnderlyingMethod + { + get { return this._method; } + } + + public override MemberInfo UnderlyingMember + { + get { return this.UnderlyingMethod; } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool RequiresInstance + { + get { return !this.UnderlyingMethod.IsStatic; } + } + + public override Type ReturnType + { + get { return this.UnderlyingMethod.ReturnType; } + } + + public override ReflectionItemType ItemType + { + get { return ReflectionItemType.Method; } + } + + public override object GetValue(object instance) + { + return SafeCreateExportedDelegate(instance, _method); + } + +#if FEATURE_CAS_APTCA + [System.Security.SecuritySafeCritical] +#endif //FEATURE_CAS_APTCA + private static ExportedDelegate SafeCreateExportedDelegate(object instance, MethodInfo method) + { + // We demand member access in place of the [SecurityCritical] + // attribute on ExportDelegate constructor + ReflectionInvoke.DemandMemberAccessIfNeeded(method); + + return new ExportedDelegate(instance, method); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionModelServices.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionModelServices.cs new file mode 100644 index 00000000000..e781bfe3494 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionModelServices.cs @@ -0,0 +1,500 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Internal; +using System.Diagnostics.Contracts; + +namespace System.ComponentModel.Composition.ReflectionModel +{ +#if FEATURE_CAS_APTCA + [System.Security.SecurityCritical] +#endif //FEATURE_CAS_APTCA + public static class ReflectionModelServices + { + public static Lazy<Type> GetPartType(ComposablePartDefinition partDefinition) + { + Requires.NotNull(partDefinition, "partDefinition"); + Contract.Ensures(Contract.Result<Lazy<Type>>() != null); + + ReflectionComposablePartDefinition reflectionPartDefinition = partDefinition as ReflectionComposablePartDefinition; + if (reflectionPartDefinition == null) + { + throw ExceptionBuilder.CreateReflectionModelInvalidPartDefinition("partDefinition", partDefinition.GetType()); + } + + return reflectionPartDefinition.GetLazyPartType(); + } + + public static bool IsDisposalRequired(ComposablePartDefinition partDefinition) + { + Requires.NotNull(partDefinition, "partDefinition"); + + ReflectionComposablePartDefinition reflectionPartDefinition = partDefinition as ReflectionComposablePartDefinition; + if (reflectionPartDefinition == null) + { + throw ExceptionBuilder.CreateReflectionModelInvalidPartDefinition("partDefinition", partDefinition.GetType()); + } + + return reflectionPartDefinition.IsDisposalRequired; + } + + public static LazyMemberInfo GetExportingMember(ExportDefinition exportDefinition) + { + Requires.NotNull(exportDefinition, "exportDefinition"); + + ReflectionMemberExportDefinition reflectionExportDefinition = exportDefinition as ReflectionMemberExportDefinition; + if (reflectionExportDefinition == null) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidExportDefinition, exportDefinition.GetType()), + "exportDefinition"); + } + + return reflectionExportDefinition.ExportingLazyMember; + } + + public static LazyMemberInfo GetImportingMember(ImportDefinition importDefinition) + { + Requires.NotNull(importDefinition, "importDefinition"); + + ReflectionMemberImportDefinition reflectionMemberImportDefinition = importDefinition as ReflectionMemberImportDefinition; + if (reflectionMemberImportDefinition == null) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidMemberImportDefinition, importDefinition.GetType()), + "importDefinition"); + } + + return reflectionMemberImportDefinition.ImportingLazyMember; + } + + public static Lazy<ParameterInfo> GetImportingParameter(ImportDefinition importDefinition) + { + Requires.NotNull(importDefinition, "importDefinition"); + Contract.Ensures(Contract.Result<Lazy<ParameterInfo>>() != null); + + ReflectionParameterImportDefinition reflectionParameterImportDefinition = importDefinition as ReflectionParameterImportDefinition; + if (reflectionParameterImportDefinition == null) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidParameterImportDefinition, importDefinition.GetType()), + "importDefinition"); + } + + return reflectionParameterImportDefinition.ImportingLazyParameter; + } + + public static bool IsImportingParameter(ImportDefinition importDefinition) + { + Requires.NotNull(importDefinition, "importDefinition"); + + ReflectionImportDefinition reflectionImportDefinition = importDefinition as ReflectionImportDefinition; + if (reflectionImportDefinition == null) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidImportDefinition, importDefinition.GetType()), + "importDefinition"); + } + + return (importDefinition is ReflectionParameterImportDefinition); + } + + public static bool IsExportFactoryImportDefinition(ImportDefinition importDefinition) + { + Requires.NotNull(importDefinition, "importDefinition"); + + ReflectionImportDefinition reflectionImportDefinition = importDefinition as ReflectionImportDefinition; + if (reflectionImportDefinition == null) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidImportDefinition, importDefinition.GetType()), + "importDefinition"); + } + + return (importDefinition is IPartCreatorImportDefinition); + } + + public static ContractBasedImportDefinition GetExportFactoryProductImportDefinition(ImportDefinition importDefinition) + { + Requires.NotNull(importDefinition, "importDefinition"); + Contract.Ensures(Contract.Result<ContractBasedImportDefinition>() != null); + + IPartCreatorImportDefinition partCreatorImportDefinition = importDefinition as IPartCreatorImportDefinition; + if (partCreatorImportDefinition == null) + { + throw new ArgumentException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidImportDefinition, importDefinition.GetType()), + "importDefinition"); + } + + return partCreatorImportDefinition.ProductImportDefinition; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ComposablePartDefinition CreatePartDefinition( + Lazy<Type> partType, + bool isDisposalRequired, + Lazy<IEnumerable<ImportDefinition>> imports, + Lazy<IEnumerable<ExportDefinition>> exports, + Lazy<IDictionary<string, object>> metadata, + ICompositionElement origin) + { + Requires.NotNull(partType, "partType"); + Contract.Ensures(Contract.Result<ComposablePartDefinition>() != null); + + return new ReflectionComposablePartDefinition( + new ReflectionPartCreationInfo( + partType, + isDisposalRequired, + imports, + exports, + metadata, + origin)); + } + + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ExportDefinition CreateExportDefinition( + LazyMemberInfo exportingMember, + string contractName, + Lazy<IDictionary<string, object>> metadata, + ICompositionElement origin) + { + Requires.NotNullOrEmpty(contractName, "contractName"); + Requires.IsInMembertypeSet(exportingMember.MemberType, "exportingMember", MemberTypes.Field | MemberTypes.Property | MemberTypes.NestedType | MemberTypes.TypeInfo | MemberTypes.Method); + Contract.Ensures(Contract.Result<ExportDefinition>() != null); + + return new ReflectionMemberExportDefinition( + exportingMember, + new LazyExportDefinition(contractName, metadata), + origin); + } + + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ContractBasedImportDefinition CreateImportDefinition( + LazyMemberInfo importingMember, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + bool isRecomposable, + CreationPolicy requiredCreationPolicy, + ICompositionElement origin) + { + return CreateImportDefinition(importingMember, contractName, requiredTypeIdentity, requiredMetadata, cardinality, isRecomposable, requiredCreationPolicy, MetadataServices.EmptyMetadata, false, origin); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ContractBasedImportDefinition CreateImportDefinition( + LazyMemberInfo importingMember, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + bool isRecomposable, + CreationPolicy requiredCreationPolicy, + IDictionary<string, object> metadata, + bool isExportFactory, + ICompositionElement origin) + { + return CreateImportDefinition( + importingMember, + contractName, + requiredTypeIdentity, + requiredMetadata, + cardinality, + isRecomposable, + false, + requiredCreationPolicy, + metadata, + isExportFactory, + origin); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ContractBasedImportDefinition CreateImportDefinition( + LazyMemberInfo importingMember, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + bool isRecomposable, + bool isPreRequisite, + CreationPolicy requiredCreationPolicy, + IDictionary<string, object> metadata, + bool isExportFactory, + ICompositionElement origin) + { + Requires.NotNullOrEmpty(contractName, "contractName"); + Requires.IsInMembertypeSet(importingMember.MemberType, "importingMember", MemberTypes.Property | MemberTypes.Field); + Contract.Ensures(Contract.Result<ContractBasedImportDefinition>() != null); + + if (isExportFactory) + { + return new PartCreatorMemberImportDefinition( + importingMember, + origin, + new ContractBasedImportDefinition( + contractName, + requiredTypeIdentity, + requiredMetadata, + cardinality, + isRecomposable, + isPreRequisite, + CreationPolicy.NonShared, + metadata)); + } + else + { + return new ReflectionMemberImportDefinition( + importingMember, + contractName, + requiredTypeIdentity, + requiredMetadata, + cardinality, + isRecomposable, + isPreRequisite, + requiredCreationPolicy, + metadata, + origin); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ContractBasedImportDefinition CreateImportDefinition( + Lazy<ParameterInfo> parameter, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + CreationPolicy requiredCreationPolicy, + ICompositionElement origin) + { + return CreateImportDefinition(parameter, contractName, requiredTypeIdentity, requiredMetadata, cardinality, requiredCreationPolicy, MetadataServices.EmptyMetadata, false, origin); + } + + [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] + public static ContractBasedImportDefinition CreateImportDefinition( + Lazy<ParameterInfo> parameter, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string, Type>> requiredMetadata, + ImportCardinality cardinality, + CreationPolicy requiredCreationPolicy, + IDictionary<string, object> metadata, + bool isExportFactory, + ICompositionElement origin) + { + Requires.NotNull(parameter, "parameter"); + Requires.NotNullOrEmpty(contractName, "contractName"); + Contract.Ensures(Contract.Result<ContractBasedImportDefinition>() != null); + + if (isExportFactory) + { + return new PartCreatorParameterImportDefinition( + parameter, + origin, + new ContractBasedImportDefinition( + contractName, + requiredTypeIdentity, + requiredMetadata, + cardinality, + false, + true, + CreationPolicy.NonShared, + metadata)); + } + else + { + return new ReflectionParameterImportDefinition( + parameter, + contractName, + requiredTypeIdentity, + requiredMetadata, + cardinality, + requiredCreationPolicy, + metadata, + origin); + } + } + + public static bool TryMakeGenericPartDefinition(ComposablePartDefinition partDefinition, IEnumerable<Type> genericParameters, out ComposablePartDefinition specialization) + { + Requires.NotNull(partDefinition, "partDefinition"); + + specialization = null; + ReflectionComposablePartDefinition reflectionPartDefinition = partDefinition as ReflectionComposablePartDefinition; + if (reflectionPartDefinition == null) + { + throw ExceptionBuilder.CreateReflectionModelInvalidPartDefinition("partDefinition", partDefinition.GetType()); + } + + return reflectionPartDefinition.TryMakeGenericPartDefinition(genericParameters.ToArray(), out specialization); + } + } + + + + internal class ReflectionPartCreationInfo : IReflectionPartCreationInfo + { + private readonly Lazy<Type> _partType; + private readonly Lazy<IEnumerable<ImportDefinition>> _imports; + private readonly Lazy<IEnumerable<ExportDefinition>> _exports; + private readonly Lazy<IDictionary<string, object>> _metadata; + private readonly ICompositionElement _origin; + private ConstructorInfo _constructor; + private bool _isDisposalRequired; + + public ReflectionPartCreationInfo( + Lazy<Type> partType, + bool isDisposalRequired, + Lazy<IEnumerable<ImportDefinition>> imports, + Lazy<IEnumerable<ExportDefinition>> exports, + Lazy<IDictionary<string, object>> metadata, + ICompositionElement origin) + { + Assumes.NotNull(partType); + + this._partType = partType; + this._isDisposalRequired = isDisposalRequired; + this._imports = imports; + this._exports = exports; + this._metadata = metadata; + this._origin = origin; + } + + public Type GetPartType() + { + return this._partType.GetNotNullValue("type"); + } + + public Lazy<Type> GetLazyPartType() + { + return this._partType; + } + + public ConstructorInfo GetConstructor() + { + if (this._constructor == null) + { + ConstructorInfo[] constructors = null; + constructors = this.GetImports() + .OfType<ReflectionParameterImportDefinition>() + .Select(parameterImport => parameterImport.ImportingLazyParameter.Value.Member) + .OfType<ConstructorInfo>() + .Distinct() + .ToArray(); + + if (constructors.Length == 1) + { + this._constructor = constructors[0]; + } + else if (constructors.Length == 0) + { + this._constructor = this.GetPartType().GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); + } + } + return this._constructor; + } + + public bool IsDisposalRequired + { + get + { + return this._isDisposalRequired; + } + } + + public IDictionary<string, object> GetMetadata() + { + return (this._metadata != null) ? this._metadata.Value : null; + } + + public IEnumerable<ExportDefinition> GetExports() + { + if (this._exports == null) + { + yield break; + } + + IEnumerable<ExportDefinition> exports = this._exports.Value; + + if (exports == null) + { + yield break; + } + + foreach (ExportDefinition export in exports) + { + ReflectionMemberExportDefinition reflectionExport = export as ReflectionMemberExportDefinition; + if (reflectionExport == null) + { + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidExportDefinition, export.GetType())); + } + yield return reflectionExport; + } + } + + public IEnumerable<ImportDefinition> GetImports() + { + if (this._imports == null) + { + yield break; + } + + IEnumerable<ImportDefinition> imports = this._imports.Value; + + if (imports == null) + { + yield break; + } + + foreach (ImportDefinition import in imports) + { + ReflectionImportDefinition reflectionImport = import as ReflectionImportDefinition; + if (reflectionImport == null) + { + throw new InvalidOperationException( + string.Format(CultureInfo.CurrentCulture, Strings.ReflectionModel_InvalidMemberImportDefinition, import.GetType())); + } + yield return reflectionImport; + } + } + + public string DisplayName + { + get { return this.GetPartType().GetDisplayName(); } + } + + public ICompositionElement Origin + { + get { return this._origin; } + } + } + + internal class LazyExportDefinition : ExportDefinition + { + private readonly Lazy<IDictionary<string, object>> _metadata; + + public LazyExportDefinition(string contractName, Lazy<IDictionary<string, object>> metadata) + : base(contractName, (IDictionary<string, object>)null) + { + this._metadata = metadata; + } + + public override IDictionary<string, object> Metadata + { + get + { + return this._metadata.Value ?? MetadataServices.EmptyMetadata; + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionParameter.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionParameter.cs new file mode 100644 index 00000000000..0d5fbf37621 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionParameter.cs @@ -0,0 +1,52 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionParameter : ReflectionItem + { + private readonly ParameterInfo _parameter; + + public ReflectionParameter(ParameterInfo parameter) + { + Assumes.NotNull(parameter); + + this._parameter = parameter; + } + + public ParameterInfo UnderlyingParameter + { + get { return this._parameter; } + } + + public override string Name + { + get { return this.UnderlyingParameter.Name; } + } + + public override string GetDisplayName() + { + return string.Format( + CultureInfo.CurrentCulture, + "{0} (Parameter=\"{1}\")", // NOLOC + this.UnderlyingParameter.Member.GetDisplayName(), + this.UnderlyingParameter.Name); + } + + public override Type ReturnType + { + get { return this.UnderlyingParameter.ParameterType; } + } + + public override ReflectionItemType ItemType + { + get { return ReflectionItemType.Parameter; } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionParameterImportDefinition.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionParameterImportDefinition.cs new file mode 100644 index 00000000000..36762a3795c --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionParameterImportDefinition.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Globalization; +using System.Reflection; +using Microsoft.Internal; +using System.ComponentModel.Composition.ReflectionModel; +using System.Collections.Generic; +using System.ComponentModel.Composition.Primitives; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionParameterImportDefinition : ReflectionImportDefinition + { + private Lazy<ParameterInfo> _importingLazyParameter; + + public ReflectionParameterImportDefinition( + Lazy<ParameterInfo> importingLazyParameter, + string contractName, + string requiredTypeIdentity, + IEnumerable<KeyValuePair<string,Type>> requiredMetadata, + ImportCardinality cardinality, + CreationPolicy requiredCreationPolicy, + IDictionary<string, object> metadata, + ICompositionElement origin) + : base(contractName, requiredTypeIdentity, requiredMetadata, cardinality, false, true, requiredCreationPolicy, metadata, origin) + { + Assumes.NotNull(importingLazyParameter); + + this._importingLazyParameter = importingLazyParameter; + } + + public override ImportingItem ToImportingItem() + { + return new ImportingParameter(this, new ImportType(this.ImportingLazyParameter.GetNotNullValue("parameter").ParameterType, this.Cardinality)); + } + + public Lazy<ParameterInfo> ImportingLazyParameter + { + get { return this._importingLazyParameter; } + } + + protected override string GetDisplayName() + { + ParameterInfo parameter = this.ImportingLazyParameter.GetNotNullValue("parameter"); + return string.Format( + CultureInfo.CurrentCulture, + "{0} (Parameter=\"{1}\", ContractName=\"{2}\")", // NOLOC + parameter.Member.GetDisplayName(), + parameter.Name, + this.ContractName); + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionProperty.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionProperty.cs new file mode 100644 index 00000000000..6daa34baa50 --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionProperty.cs @@ -0,0 +1,124 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + // Instead of representing properties as an actual PropertyInfo, we need to + // represent them as two MethodInfo objects one for each accessor. This is so + // that cached attribute part can go from a metadata token -> XXXInfo without + // needing to walk all members of a particular type. Unfortunately, (probably + // because you never see one of them in an IL stream), Reflection does not allow + // you to go from a metadata token -> PropertyInfo like it does with types, + // fields, and methods. + + internal class ReflectionProperty : ReflectionWritableMember + { + private readonly MethodInfo _getMethod; + private readonly MethodInfo _setMethod; + + public ReflectionProperty(MethodInfo getMethod, MethodInfo setMethod) + { + Assumes.IsTrue(getMethod != null || setMethod != null); + + this._getMethod = getMethod; + this._setMethod = setMethod; + } + + public override MemberInfo UnderlyingMember + { + get { return this.UnderlyingGetMethod ?? this.UnderlyingSetMethod; } + } + + public override bool CanRead + { + get { return this.UnderlyingGetMethod != null; } + } + + public override bool CanWrite + { + get { return this.UnderlyingSetMethod != null; } + } + + public MethodInfo UnderlyingGetMethod + { + get { return this._getMethod; } + } + + public MethodInfo UnderlyingSetMethod + { + get { return this._setMethod; } + } + + public override string Name + { + get + { + MethodInfo method = this.UnderlyingGetMethod ?? this.UnderlyingSetMethod; + + string name = method.Name; + + Assumes.IsTrue(name.Length > 4); + + // Remove 'get_' or 'set_' + return name.Substring(4); + } + } + + public override string GetDisplayName() + { + return ReflectionServices.GetDisplayName(this.DeclaringType, this.Name); + } + + public override bool RequiresInstance + { + get + { + MethodInfo method = this.UnderlyingGetMethod ?? this.UnderlyingSetMethod; + + return !method.IsStatic; + } + } + + public override Type ReturnType + { + get + { + if (this.UnderlyingGetMethod != null) + { + return this.UnderlyingGetMethod.ReturnType; + } + + ParameterInfo[] parameters = this.UnderlyingSetMethod.GetParameters(); + + Assumes.IsTrue(parameters.Length > 0); + + return parameters[parameters.Length - 1].ParameterType; + } + } + + public override ReflectionItemType ItemType + { + get { return ReflectionItemType.Property; } + } + + public override object GetValue(object instance) + { + Assumes.NotNull(this._getMethod); + + return this.UnderlyingGetMethod.SafeInvoke(instance); + } + + public override void SetValue(object instance, object value) + { + Assumes.NotNull(this._setMethod); + + this.UnderlyingSetMethod.SafeInvoke(instance, value); + } + + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionType.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionType.cs new file mode 100644 index 00000000000..b6ff302dbaf --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionType.cs @@ -0,0 +1,53 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.ComponentModel.Composition.AttributedModel; +using System.Reflection; +using Microsoft.Internal; +using System.Threading; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal class ReflectionType : ReflectionMember + { + private Type _type; + + public ReflectionType(Type type) + { + Assumes.NotNull(type); + + this._type = type; + } + + public override MemberInfo UnderlyingMember + { + get { return this._type; } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool RequiresInstance + { + get { return true; } + } + + public override Type ReturnType + { + get { return this._type; } + } + + public override ReflectionItemType ItemType + { + get { return ReflectionItemType.Type; } + } + + public override object GetValue(object instance) + { + return instance; + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionWritableMember.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionWritableMember.cs new file mode 100644 index 00000000000..b8cf56d340d --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/ReflectionModel/ReflectionWritableMember.cs @@ -0,0 +1,19 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Reflection; +using Microsoft.Internal; + +namespace System.ComponentModel.Composition.ReflectionModel +{ + internal abstract class ReflectionWritableMember : ReflectionMember + { + public abstract bool CanWrite + { + get; + } + + public abstract void SetValue(object instance, object value); + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/LazyOfTTMetadata.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/LazyOfTTMetadata.cs new file mode 100644 index 00000000000..aba65fb5a6a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/LazyOfTTMetadata.cs @@ -0,0 +1,62 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace System +{ + [Serializable] + public class Lazy<T, TMetadata> : Lazy<T> + { + private TMetadata _metadata; + + public Lazy(Func<T> valueFactory, TMetadata metadata) : + base(valueFactory) + { + this._metadata = metadata; + } + + public Lazy(TMetadata metadata) : + base() + { + this._metadata = metadata; + } + + + public Lazy(TMetadata metadata, bool isThreadSafe) : + base(isThreadSafe) + { + this._metadata = metadata; + } + + public Lazy(Func<T> valueFactory, TMetadata metadata, bool isThreadSafe) : + base(valueFactory, isThreadSafe) + { + this._metadata = metadata; + } + + public Lazy(TMetadata metadata, LazyThreadSafetyMode mode) : + base(mode) + { + this._metadata = metadata; + } + + public Lazy(Func<T> valueFactory, TMetadata metadata, LazyThreadSafetyMode mode) : + base(valueFactory, mode) + { + this._metadata = metadata; + } + + public TMetadata Metadata + { + get + { + return this._metadata; + } + } + } +} diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/VersionInfo.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/VersionInfo.cs new file mode 100644 index 00000000000..1f7bf88888a --- /dev/null +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/VersionInfo.cs @@ -0,0 +1,14 @@ +// ----------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ----------------------------------------------------------------------- +using System; +using System.Runtime.CompilerServices; +using System.Security; + +[assembly: System.Reflection.AssemblyTitle("System.ComponentModel.Composition.CodePlex")] +[assembly: System.Reflection.AssemblyCopyright("(c) Microsoft Corporation. All rights reserved.")] +[assembly: System.Reflection.AssemblyDescription("Codeplex version (http://mef.codeplex.com)")] +[assembly: System.Reflection.AssemblyVersion("4.1.2.0")] +[assembly: System.Reflection.AssemblyFileVersion("1.1.0.0")] + + |