Closed GoogleCodeExporter closed 8 years ago
I think this is functioning as designed.
Here's a more concrete test that I ran:
void Main()
{
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterGeneric(typeof(Concrete<>)).As(typeof(IContravariant<>));
var container = builder.Build();
var list = container.Resolve<IEnumerable<IContravariant<string>>>();
foreach(var item in list)
{
Console.WriteLine(item.GetType());
}
}
public interface IContravariant<in T> {}
public class Concrete<T> : IContravariant<T>{}
The output of that was:
typeof (Concrete<String>)
typeof (Concrete<Object>)
typeof (Concrete<IComparable>)
typeof (Concrete<ICloneable>)
typeof (Concrete<IConvertible>)
typeof (Concrete<IComparable<String>>)
typeof (Concrete<IEnumerable<Char>>)
typeof (Concrete<IEnumerable>)
typeof (Concrete<IEquatable<String>>)
Given the definition of "contravariant"
(http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
and http://msdn.microsoft.com/en-us/library/dd799517.aspx) - converting from a
more general type to a specific type, it makes sense that the contravariant
source would provide a generic that has the specific concrete type AND the
generics for all of the interfaces and base types the concrete type implements.
It also appears that's the intent of the source as written
(https://code.google.com/p/autofac/source/browse/Core/Source/Autofac/Features/Va
riance/ContravariantRegistrationSource.cs).
I'm not entirely sure it was intended to resolve an IEnumerable of all of the
contravariant types, but when doing it... it does appear to be functioning as
designed.
I noticed in the issue report that the interface defined in step 1 of the repro
was marked with an "out" generic type - that's covariant, not contravariant,
but I'm not sure if that was just a typo.
Original comment by travis.illig
on 6 Mar 2013 at 4:59
Well, if you want to know why I am resolving IEnumerable<IValidator<T>>, I can
try to explain.
I am trying to resolve and run all validators registered for a given type. One
of them (and the one which is always there) is DataAnnotationValidator<T>. The
described behavior results in that Autofac will resolve N validators
constructed from DataAnnotationValidator<> that under the hood run the same
code, thus duplicating validation errors.
I think that in the given circumstances Autofac should only return an
implementation constructed for most specific type. Could you think of any case
when you would want to resolve implementations for ALL types in hierarchy?
Original comment by Eugene.S...@gmail.com
on 7 Mar 2013 at 8:09
Yep, the interface being covariant was a typo. Sorry.
Original comment by Eugene.S...@gmail.com
on 7 Mar 2013 at 8:11
I can't think of a time where I've ever needed the
ContravariantRegistrationSource, so I've never run into the trouble you're
finding. I actually have applications that perform exactly the function you're
mentioning and have no issues... but without that source in the pipeline.
The source itself is behaving as it should, and the collections support is also
behaving; it's a weird conjunction between the two causing problems and I'm not
sure it's something we could (or should) fix.
I might recommend taking the code from ContravariantRegistrationSource and
modifying it to behave to your liking. Maybe it needs to be a
CollectionAwareContravariantRegistrationSource or something like that.
Original comment by travis.illig
on 7 Mar 2013 at 8:15
Original issue reported on code.google.com by
Eugene.S...@gmail.com
on 5 Mar 2013 at 10:39