Search code examples
c#ambiguous-call

Default overload for ambiguous calls


Say I have the following two functions:

void Foo(IEnumerable<string> bar)
{
  if(bar == null)
    return;
  foreach(var b in bar)
  {
    Console.Write(b);
  }
}    

and

void Foo(string bar)
{
   Foo(new string[] { bar });
}

Those two are ambiguous if I'm passing null as a parameter.

Is there a way to hint the compiler to disambiguate the overload? Any attribute or directive or something? In this case, I'd like the first function to be called. Something like:

[InCaseOfAmbiguityUseThis]
public void Foo(IEnumerable<string> bar)

So that if I Foo(null) the compiler will know where to look for and not complain.

I've been looking for a while and haven't found anything to the respect.

PS: I know I can use: Foo((IEnumerable<string>)null) but that's what I'm trying to avoid: the types in the real functions are quite long and use generic constraints (so I can't just inherit the type to make it shorter), so it dirties the code a lot.

I don't mind it being 'dirty' in the libraries (where I'm specifying those functions) but not on the actual business code (where I'm calling those functions).

Also, there might be a lot of these possibly ambiguous functions, so "a workaround to not make them ambiguous" is out of the question (that's what I'm using now, but I don't like having such boilerplate code)

Edit

I'm not looking for workarounds (i.e., making other functions with different or no parameters). I know all these ways, and as I specified, I'm already using that. Just wondering if it's actually possible to make the compiler disambiguate "automatically".

I'd prefer not to have a parameterless function (the real function is much more verbose passing a null parameter than passing no parameter at all):

Task<IEnumerable<TResult>> GetAsyncProjected<TResult>(
    IEnumerable<Expression<Func<T, bool>>> filters,
    Expression<Func<T, TResult>> projection,
    IEnumerable<string> eagerLoadRelationships,
    CancellationToken cancellationToken,
    ServiceRefreshMode refreshMode);

Task<IEnumerable<TResult>> GetAsyncProjected<TResult>(
    Expression<Func<T, bool>> filter,
    Expression<Func<T, TResult>> projection,
    IEnumerable<string> eagerLoadRelationships,
    CancellationToken cancellationToken,
    ServiceRefreshMode refreshMode);

// ... plenty of overloads for each possible parameter ...

I do have another overload for each of those overloads without the filter/filters parameter but I'd prefer not to so that the caller knows it's passing null for the filter explcitly.

If there is no way, then I'll look for other ways (calling it GetAsyncFilteredProjected() if it has a parameter or something)


Solution

  • There's no way to customize overloading in C# like this. There're strict rules of choosing a method overload.

    However, if you want to provide a version of the method without the argument, you can just create a new overload instead of passing null:

    void Foo()
    {
        Foo((string)null);
    }
    

    It would be more readable, as a bonus.

    Also, if you can't modify original classes and they don't provide overloads you need, you can use extension methods. This will keep business logic clean.