5

C# Case-Insensitive List.Contains(): No overload for method 'Contains' takes 2 arguments

Got compiler error if we do

list.Contains(stringToSearchDynamic.ToString(), StringComparer.OrdinalIgnoreCase)

But compiles OK if we put actual string

list.Contains(stringToSearch, StringComparer.OrdinalIgnoreCase)

Is this a compiler bug ?

Code:

List<string> list = new List<string>();
list.Add("one");
list.Add("two");

string stringToSearch = "OnE";
dynamic stringToSearchDynamic = "OnE";

//compiles OK
bool isContained = list.Contains(stringToSearch, StringComparer.OrdinalIgnoreCase);


//Does NOT compile
isContained = list.Contains(stringToSearchDynamic.ToString(), StringComparer.OrdinalIgnoreCase);
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Lydon Ch
  • 8,637
  • 20
  • 79
  • 132

4 Answers4

9

The type of a dynamic expression is also dynamic. Since you have a dynamic variable the type of variable.ToString is resolved at runtime, not at compile time. So it's treated as dynamic and compiler can't find a Contains method that takes dynamic as first argument.

You can cast to string as suggested in the comments, it works because casting is a compile-time thing and makes the compiler treat your variable as string.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • @PanagiotisKanavos care to elaborate why? – Selman Genç Mar 18 '19 at 08:08
  • 1
    The error text itself complains about `Contains` with two arguments, not about a type mismatch. Now that I think of it though, `List.Contains()` uses only *one* argument. The OP is trying to use `Enumerable.Contains` but the compiler tries to use `List.Contains` instead – Panagiotis Kanavos Mar 18 '19 at 08:11
  • if you try with an int you still get the same error message: `list.Contains(2, StringComparer.OrdinalIgnoreCase);` the compiler first searches instance methods, then extension methods, but since there is no method that takes dynamic as first argument it generates this error. – Selman Genç Mar 18 '19 at 08:16
4

Use a simple cast instead of ToString(). ToString() is essentially a no-op when applied to string instances anyway, it just returns the string itself. This compiles :

isContained = list.Contains((string)stringToSearchDynamic, StringComparer.OrdinalIgnoreCase);

Explanation

The original code is trying to use the Enumerable.Contains extension method which accepts a comparer as a second argument. The method's signature is Contains<TSource>(IEnumerable<TSource>, TSource, IEqualityComparer<TSource>). This means that the value to search itself must be TSource. In this case though, it's dynamic and unknown until runtime.

The compiler won't even try to use the extension method and try to find a Contains on List itself. What it finds though is a List.Contains(T) that only accepts a single parameter and complains about multiple arguments

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
0

I was using .NetFrameWork 4.7.2 and it was working fine but due to some reasons I had to use .NetFrameWork 2.0 and here it was giving similar error. so if you can use latest framework version it can help.

0

Note that if you have this error without a reasonable explanation, this behaviour has been changed from .NET standard 2.0 => 2.1. So if you're working in a .NET Standard 2.0 or .NET Framework solution, this overload effectively does not exist.

Solution can be to use a workaround (eg. create your own extension method), or update the solution to .NET Standard 2.1. The second option sounds like a huge overkill for this use case, and will not be compatible with .NET Framework solutions.

Wimpix
  • 11
  • 3