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

本文关键字:命名空间 顺序 失败 检查 方法 扩展 编译 兼容性 | 更新日期: 2023-09-27 18:14:16

我正在编写两个扩展方法。一种用于处理单个对象,另一种用于处理对象集合。当调用扩展方法时,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);
    }
}

这是编译失败的调用行:

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

失败,错误CS0311:

类型是System.Collections.Generic。List'不能用作泛型类型或方法' lang . mi . dbobjectextensions '中的类型参数'T'。populaterrelationships (T, params granda . mi . relationtoprefetch[])'。没有从"System.Collections.Generic"的隐式引用转换。把' List'列到' grand . 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);
}

为什么编译器不能找出有一个匹配的扩展方法?更令人困惑的是,如果我把其中一个方法放在不同的命名空间中,并且包含了那个命名空间,为什么编译会成功?有什么我能做的吗?

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

一般约束不是方法签名的一部分,所以编译器选择PopulateRelations<T>(this T obj, params RelationToPrefetch[] relationsToPrefetch),因为TIEnumerable<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

因为list直接匹配List<ITable>

泛型类型被限制为IDBObject,因此您可以将扩展方法设置为非泛型:

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

解决编译错误