Prima di tutto cerchiamo di descrivere ciò che provoca esattamente questo comportamento.
RegistrationBuilder racchiude i tipi effettivi dell'assieme in un tipo di proxy denominato CustomType. Questo proxy esiste più o meno solo per dare al RegistrationBuilder l'opportunità di iniettare gli attributi di esportazione e importazione al volo.
Purtroppo questo proxy restituisce anche i tipi avvolti quando si chiama GetGenericParameterConstraints. Quindi non è un RuntimType IItem si ottiene un CustomType IItem. Quando si tenta di ottenere un'esportazione per IConstrained, AssemblyCatalog controlla un sacco di cose per sapere se l'esportazione coincide con l'importazione. Uno di questi controlli è se il vincolo di tipo generico è soddisfatto. È più o meno un assegno come questo. (Semplificato)
exportToCheck.GenericTypeConstraints[0].IsAssignableFrom(typeof(Item))
Il metodo IsAssignableForm del CustomType è implementato come questo.
public override bool IsAssignableFrom(Type c)
{
ProjectingType projectingType = c as ProjectingType;
return !(projectingType == null) && this.Projector == projectingType.Projector &&
base.UnderlyingType.IsAssignableFrom(projectingType.UnderlyingType);
}
Funziona solo se si passa un altro tipo di proxy.
Penso davvero che sia un grosso problema di RegistrationBuilder e dovresti segnalarlo a Microsoft Connect.
Per aggirare questo problema, è necessario annullare la creazione di GenericTypeContraints salvati con ComposablePartDefinition.
La cattiva notizia è che tutte le classi rilevanti sono interne, quindi non è possibile sovrascrivere il metodo GetGenericParameterConstraints.
Ho risolto questo problema ereditando AssemblyCatalog e non proiettando manualmente i tipi di vincoli.
public class MyAssemblyCatalog: AssemblyCatalog { privato Func unprojectDelegate;
private bool projectionsChecked = false;
public MyAssemblyCatalog(Assembly assembly, CustomReflectionContext reflectionContext)
: base(assembly, reflectionContext)
{
this.ReflectionContext = reflectionContext;
}
public CustomReflectionContext ReflectionContext { get; private set; }
public Type Unproject(Type type)
{
if (this.unprojectDelegate == null) {
var param = Expression.Parameter(typeof(CustomReflectionContext));
var param2 = Expression.Parameter(typeof(Type));
var prop = Expression.Property(param, param.Type.GetProperty("Projector", BindingFlags.Instance | BindingFlags.NonPublic));
var method = prop.Type.GetMethod("Unproject", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(Type) }, null);
var body = Expression.Call(prop, method, param2);
this.unprojectDelegate = Expression.Lambda<Func<CustomReflectionContext, Type, Type>>(body, param, param2).Compile();
}
return unprojectDelegate(this.ReflectionContext, type);
}
private void EnsureUnprojectedGenericTypeConstraints()
{
if (!this.projectionsChecked) {
foreach (var item in this) {
object value1;
if (item.Metadata.TryGetValue("System.ComponentModel.Composition.GenericParameterConstraints", out value1)) {
var items = (object[])value1;
foreach (var entry in items) {
var types = entry as Type[];
if (types != null) {
for (int i = 0; i < types.Length; i++) {
types[i] = Unproject(types[i]);
}
}
}
}
}
projectionsChecked = true;
}
}
public override System.Collections.Generic.IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
{
EnsureUnprojectedGenericTypeConstraints();
return base.GetExports(definition);
}
}
Ora il test funziona. soluzione
[TestMethod]
public void TypeConstraintTest()
{
var rb = new RegistrationBuilder();
var a = new MyAssemblyCatalog(Assembly.GetExecutingAssembly(), rb);
var aggr = new AggregateCatalog(a);
var c = new CompositionContainer(aggr);
var item = c.GetExportedValue<IConstrained<Item>>();
Assert.IsNotNull(item);
}
prega di elaborare, var rb = new RegistrationBuilder(); var a = nuovo AssemblyCatalog (Assembly.GetExecutingAssembly(), rb); rb è inutilizzato, semplicemente non fare nulla – InferOn
Non fa ancora nulla cambia comportamento, cioè rompe i generici aperti. Il piano è di usarlo una volta il caso base, basta passarlo, funziona. –