如何确保正确的扩展方法解析

时间:2016-10-19 13:24:34

标签: c# extension-methods overload-resolution

我在扩展方法解析中看到了一些意想不到的行为,并且我试图找出原因。我已阅读Eric Lippert's Closer is Better文章,我仍感到困惑。

首先是呼叫站点:

// Assembly: DLaB.Xrm.2016.Tests
using DLaB.Xrm.Entities;
using DLaB.Xrm.Test;
using Microsoft.Xrm.Sdk;

namespace DLaB.Xrm.Tests 

    public class TrialClass{
    {
        public void Delete(){
            IOrganziationService service = GetService();
            Id<Contact> id = GetId();
            service.Delete(id);  // Call Site in Question
        }
    } 
}

IOrganizationService使用此签名定义删除方法:

// Assembly: Microsoft.Xrm.Sdk
void Delete(string entityName, Guid id);

我已经在两个不同的程序集中的两个不同的名称空间中定义了IOrganziationService上的Extension方法重载:

//Assembly: DLaB.Xrm.2016
//Namespace DLaB.Xrm
public static void Delete(this IOrganizationService service, Entity entity) { ... }
public static void Delete(this IOrganizationService service, EntityReference entity) { ... }


//Assembly: DLaB.Xrm.Test.2016
//Namespace DLaB.Xrm.Test
public static void Delete(this IOrganizationService service, Id id) { ... }
public static void Delete<T>(this IOrganizationService service, Id<T> entity) where T : Entity { ... }

我还为Id类定义了隐式运算符,将其转换为EntityEntityReference

  

呼叫站点service.Delete(id)显示编译器错误:   错误CS0121以下方法或之间的调用不明确   properties:&#39; Extensions.Delete(IOrganizationService,Entity)&#39;和   &#39; Extensions.Delete(IOrganizationService,EntityReference)&#39;

我从我已经定义的隐含算子中理解了这一点。我不理解的是DLaB.Xrm命名空间比DLaB.Xrm.Test命名空间更接近的原因,即使我没有使用using指令。

1 个答案:

答案 0 :(得分:1)

Eric的博客中定义了6条贴近规则:

  1. 首先在派生类中声明的方法比在基类中首次声明的方法更接近。
  2. 嵌套类中的方法比包含类中的方法更接近。
  3. 接收类型的任何方法都比任何扩展方法更接近。
  4. 在嵌套命名空间中的类中找到的扩展方法比在外部命名空间中的类中找到的扩展方法更接近。
  5. 在当前命名空间的类中找到的扩展方法比在using指令提到的命名空间中的类中找到的扩展方法更接近。
  6. 在using指令中提到的命名空间中的类中找到的扩展方法,其中指令位于嵌套命名空间中,而不是在using指令中提到的命名空间中的类中找到的扩展方法,其中指令位于外名称空间。
  7. 前三个不适用,因为没有适用于接口的方法。 第四是关键。 DLaB.Xrm位于嵌套的命名空间中,即使它位于不同的程序集中。我错误地认为你必须列出扩展方法的using指令才能从另一个类访问它。我现在知道嵌套命名空间中的扩展方法是自动可用的。

    namespace DLaB.Xrm.Tests更改为namespace NotNested.DLaB.Xrm.Tests会消除所有接近规则,并且通过正常签名重载决策规则解决模糊呼叫。我使用的实际修复只是使Delete调用泛型,这消除了争用中的两个隐式转换重载,并允许将调用解析为我的首选方法。