Error with list <T>. Contains (T) in LINQ query
I wonder why this is not working. Insight is appreciated.
static void Main(string[] args) { List<int> foo = new List<int> { 1, 2, 3 }; var myResult = MyTest<int>(foo); } private static List<int> MyTest<T>(List<T> input) { List<int> bar = new List<int> { 2, 3, 4 }; return bar.Where(b => input.Contains(b)).ToList(); } The expected result from MyTest () is List {2, 3}. However, the compiler reports two errors in input.Contains(b) , as shown below:
Argument 1: cannot convert from 'int' to 'T'
The best overloaded method match for 'System.Collections.Generic.List.Contains (T)' has some invalid arguments
This Where () clause works fine if I don't use shared lists.
This is a simplification of my real problem, so please do not dwell on "why are you writing this?" The problem is the error and its occurrence.
Revised for (hopefully) clarity:
namespace SandBox { class Foo { public int FooInt { get; set; } public string FooString { get; set; } } class Program { private static List<Foo> fooList = new List<Foo> { new Foo() {FooInt = 1, FooString = "A"}, new Foo() {FooInt = 2, FooString = "B"}, new Foo() {FooInt = 3, FooString = "C"} }; static void Main(string[] args) { List<int> myIntList = new List<int> { 1, 2 }; var myFirstResult = GetFoos<int>(myIntList); List<string> myStringList = new List<string> { "A", "B" }; var mySecondResult = GetFoos<string>(myStringList); } /// <summary> /// Return a list of Foo objects that match the input parameter list /// </summary> private static List<Foo> GetFoos<T>(List<T> input) { //*** // Imagine lots of code here that I don't want to duplicate in // an overload of GetFoos() //*** if (input is List<int>) { //Use this statement if a list of integer values was passed in return fooList.Where(f => input.Contains(f.FooInt)); } else if (input is List<string>) { //Use this statement if a list of string values was passed in return fooList.Where(f => input.Contains(f.FooString)); } else return null; } } } The same compiler errors are reported to input.Contains(f.Property) .
Try the following:
static void Main(string[] args) { List<int> foo = new List<int> { 1, 2, 3 }; var myResult = MyTest<int>(foo); } private static List<int> MyTest<T>(List<T> input) { List<int> bar = new List<int> { 2, 3, 4 }; return bar.Where(b => input.OfType<int>().Contains(b)).ToList(); } The problem is that the compiler has no idea what type T is. Since T can be anything, you cannot call the method that int ( input.Contains ) expects.
Just look at this feature in isolation.
private static List<int> MyTest<T>(List<T> input) { List<int> bar = new List<int> { 2, 3, 4 }; return bar.Where(b => input.Contains(b)).ToList(); } What if T was an object ... or a string .. nothing stopped T from these types there. If T was one of these types, the statement input.Contains(b) would not make sense.
The compiler complains because you allow types that do not make sense with instructions in the body of the method.
also another solution
static void MainT(string[] args) { List<int> foo = new List<int> { 1, 2, 3 }; var myResult = MyTest<int>(foo); } private static List<int> MyTest<T>(List<T> input) where T : IEquatable<int> { List<int> bar = new List<int> { 2, 3, 4 }; return bar.Where(b => input.Any(i => i.Equals(b))).ToList(); } The compiler cannot guarantee that any value of <T> - any <T> , DateTime, object, whatever - will be bound to int. That is why you get your first mistake.
In some cases, you can specify the type of an object in the signature of your function:
private static List<int> MyTest<T>(List<T> input) where T : someObject This will not work for your case, because int is a structure. You can work with it in many other ways (other answers provide some excellent methods), but you will have to somehow change your current strategy.