// -----------------------------------------------------------------------
// 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(IEnumerable<KeyValuePair<string, Type>> requiredMetadata)
{
ParameterExpression parameter = Expression.Parameter(typeof(ExportDefinition), "exportDefinition");
Expression metadataConstraintBody = null;
if (requiredMetadata != null)
{
metadataConstraintBody = ConstraintServices.CreateMetadataConstraintBody(requiredMetadata, parameter);
}
if (metadataConstraintBody != null)
{
return Expression.Lambda<Func<ExportDefinition, bool>>(metadataConstraintBody, parameter);
}
return null;
}
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;
}
}
}
|