C#扩展方法编译/兼容性检查失败,基于命名空间的顺序

时间:2015-09-23 14:31:18

标签: c# generics extension-methods

我正在编写两种扩展方法。一个用于处理单个对象,另一个用于处理对象集合。在调用扩展方法时,C#编译器似乎对使用哪一个感到困惑,并且编译失败。

更令人惊讶的是,如果我将扩展方法移动到不同的命名空间,即使我在调用点中包含两个命名空间,只有在命名空间按字母顺序排列的情况下编译才会失败 - 切换命名空间会导致编译成功。

以下是代码:

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);
    }
}

这是编译失败的callsite行:

List<ITable> list = ... // ITable inherits from IDBObject
list.PopulateRelations(xxx);

失败,错误CS0311:

  

类型'System.Collections.Generic.List'不能用作泛型类型或方法'Granta.MI.DBObjectExtensions.PopulateRelations(T,params Granta.MI.RelationToPrefetch [])'中的类型参数'T' 。没有从'System.Collections.Generic.List'到'Granta.MI.IDBObject'的隐式引用转换。

请注意,如果我删除第二个扩展方法,则此行会成功编译。

另请注意,编写蹦床方法(适用于所有可能类型的集合......)也有效:

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);
}

为什么编译器无法找出匹配的扩展方法?更令人困惑的是,如果我将其中一个方法放在不同的命名空间中,并且我包含该命名空间,为什么编译会成功呢?我能做些什么来解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

通用约束不是方法签名的一部分,因此编译器选择PopulateRelations<T>(this T obj, params RelationToPrefetch[] relationsToPrefetch)因为T的派生程度高于IEnumerable<T>

示例,介于这两种方法之间:

public static void PopulateRelations(this List<ITable> obj, params RelationToPrefetch[] relationsToPrefetch)
{
    // Do something
}

public static void PopulateRelations(this IEnumerable<ITable> objects, params RelationToPrefetch[] relationsToPrefetch)
{
    // Do something
}

在致电时选择第一个:

List<ITable> list;
PopulateRelations(list, something); // Not calling as extension method to more clear

因为listList<ITable>

直接匹配

答案 1 :(得分:0)

您的泛型类型被约束为IDBObject,因此您可以将扩展方法设为非泛型:

public static void PopulateRelations(this IDBObject obj, params RelationToPrefetch[] relationsToPrefetch)
{
    //...
}

public static void PopulateRelations(this IEnumerable<IDBObject> objects, params RelationToPrefetch[] relationsToPrefetch)
{
    //...
}

它解决了编译错误。