使用不同参数重载方法对.NET的误解(Call Ambiguous)

Moh*_*esh 14 c# polymorphism

我有一些重载方法的问题,我会尝试给它一个简单的实现.

所以这里有一个类包含以下两种方法:

public class MyRepo<TEntity>
{
    public List<TEntity> GetData(Expression<Func<TEntity, Boolean>> expression)
    {
        //Do something
    }

    public List<TEntity> GetData(Func<TEntity,Boolean> whereClause)
    {
        //Do something
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的实体:

public class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我正在使用它的地方:

{
    ...
    MyRepo<MyEntity> myRepo = new MyRepo<MyEntity>();
    myRepo.GetData(x => x.Id == 1); // The ambiguity point
    ...
}
Run Code Online (Sandbox Code Playgroud)

问题是我只有两个具有相同名称和不同参数的方法,因此,基于OOP多态性概念,我希望.NET能够理解我想要的方法.

但很明显.NET 无法理解,因为实例形式Expression<Func<TEntity, Boolean>>Func<TEntity, Boolean>是相同的,这里面.NET引发编译时错误:

The call is ambiguous between the following methods or properties:
    'Program.MyRepo<TEntity>.GetData(Expression<Func<TEntity, bool>>)' and
    'Program.MyRepo<TEntity>.GetData(Func<TEntity, bool>)'
Run Code Online (Sandbox Code Playgroud)

问题是:如何防止这个编译时错误?

我的偏好是不要触摸我GetData()在这条线上打电话的方式:

myRepo.GetData(x => x.Id == 1);
Run Code Online (Sandbox Code Playgroud)

Ale*_*kov 12

Lambda表达式(x=> x.Id==1)本身没有类型 - 当已知类型时,它们会自动"强制转换"为表达式或匹配类型的Func/delegate .也就是说为什么必须在作为普通的Delegate参数提供时转换lambda表达式,在不同的委托类型之间处理类似的问题.

在您的情况下,潜在候选人的方法表明变体和编译器都无法做出选择.

如果你真的必须保持同名,那么调用者必须自己指定类型:

 myRepo.GetData((Expression<Func<TEntity, Boolean>>)(x => x.Id == 1));
 myRepo.GetData((Func<TEntity, Boolean>)(x => x.Id == 2));
Run Code Online (Sandbox Code Playgroud)

我不认为你可以使用扩展方法作为替代方法之一,因为搜索将在类级别停止.所以真正拥有不同名称的方法是唯一真正的选择(如果你需要两者).考虑一下Expression版本是否足够.或者你可以在不同类(类似的附加功能如何平分他们IQueryable采取Expression当类似的方法IEnumerable采取Func键(见QueryableExtenasions).


Sia*_*ash 8

我相信你可以摆脱过载混乱的最简单方法是在将输入发送到函数之前输入你的输入.这可以隐式(内联)或以定义输入(推荐方式)而不是匿名输入的形式完成.这是我测试这个的方式,它的工作原理没有发出警告.

MyRepo<MyEntity> myRepo = new MyRepo<MyEntity>();
Func<MyEntity, bool> predicate = x => x.Id == 1;
Expression<Func<MyEntity, bool>> expression = x => x.Id == 1;
// both below lines are fine now
myRepo.GetData(predicate);
myRepo.GetData(expression);
Run Code Online (Sandbox Code Playgroud)

显然,C#编译器不够精确,无法区分这两者,因为它需要一些启发式行为,而匿名输入本质上是相同的.无论如何,这种解决方法可以解决问题.