Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Misunderstanding of .NET on overloaded methods with different parameters (Call Ambiguous)

I have a problem with some overloaded methods and I will try to give a simple implementation of it.

So here is a class contains two methods below:

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

and this my entity:

public class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Here is where I'm utilizing it:

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

The problem is that I just have two methods with same name and different arguments so, based on OOP polymorphism concepts, I expect .NET to understand my desired method.

But it's obvious .NET cannot understand it because the instance form of Expression<Func<TEntity, Boolean>> and Func<TEntity, Boolean> are the same and this the compile-time error which .NET raises:

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>)'

The question is: how can I prevent this compile-time error?

My preference is to do not touch the way I'm calling GetData() at this line:

myRepo.GetData(x => x.Id == 1);
like image 472
Mohammad Nikravesh Avatar asked Jan 02 '19 04:01

Mohammad Nikravesh


People also ask

Can method overloading have different return type c#?

The compiler does not consider the return type while differentiating the overloaded method. But you cannot declare two methods with the same signature and different return type. It will throw a compile-time error. If both methods have the same parameter types, but different return type, then it is not possible.

Why we use method overloading in C#?

Method overloading allows programmers to use multiple methods with the same name. The methods are differentiated with their number and type of method arguments. Method overloading is an example of the polymorphism feature of an object oriented programming language.


1 Answers

Lambda expressions (x=> x.Id==1) do not have type by themselves - they automatically "cast" to Expression or Func/delegate of matching type when type is known. I.e. Why must a lambda expression be cast when supplied as a plain Delegate parameter deals with similar issue just between different delegate types.

In your case methods that are potential candidate suggest both variants and compiler can't make a choice.

If you really have to keep same name then callers will have to specify type themselves:

 myRepo.GetData((Expression<Func<TEntity, Boolean>>)(x => x.Id == 1));
 myRepo.GetData((Func<TEntity, Boolean>)(x => x.Id == 2));

I don't think you can use extension method for one of alternatives as search will stop at the class level. So really having methods with different names is the only real option (if you need both). Consider if just Expression version is enough. Alternatively you can split them between different classes (similar how extensions of IQueryable take Expression when similar methods on IEnumerable take Func (see QueryableExtenasions).

like image 164
Alexei Levenkov Avatar answered Sep 17 '22 18:09

Alexei Levenkov