I am writing two extension methods. One for working on one object, and the other for working with a collection of objects. When calling the extension method, the C # compiler seems to get confused as to which one to use, and does not compile.
More surprisingly, if you move extension methods to different namespaces, even if I include both namespaces in callsite, compilation will fail if the namespaces are in a certain order alphabetically - switching namespaces will result in successful compilation.
Here is the code:
public static class DBObjectExtensions { public static void PopulateRelations<T>(this T obj, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject { if (obj == null) { return; } obj.Transaction.PopulateRelations<T>(new[]{ obj }, relationsToPrefetch); } public static void PopulateRelations<T>(this IEnumerable<T> objects, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject { var first = objects.FirstOrDefault(); if (first == null) { return; } first.Transaction.PopulateRelations<T>(objects, relationsToPrefetch); } }
This is a call line that does not compile:
List<ITable> list = ...
Error with error CS0311:
The type "System.Collections.Generic.List" cannot be used as a parameter of type "T" in the generic type or method "Granta.MI.DBObjectExtensions.PopulateRelations (T, params Granta.MI.RelationToPrefetch []) ', There is no implicit conversion links from "System.Collections.Generic.List" to "Granta.MI.IDBObject".
Note that this line compiles successfully if I remove the second extension method.
Also note that using trampoline methods (for every possible type of collection ...) also works:
public static void PopulateRelations<T>(this List<T> objects, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject { ((IEnumerable<T>)objects).PopulateRelations(relationsToPrefetch); } public static void PopulateRelations<T>(this IList<T> objects, params RelationToPrefetch[] relationsToPrefetch) where T : IDBObject { ((IEnumerable<T>)objects).PopulateRelations(relationsToPrefetch); }
Why can't the compiler find a suitable extension method? And even more vaguely, if I put one of the methods in a different namespace and I include this namespace, why will the compilation succeed? Is there anything I can do to fix this?