Linq - IQueryable Casting for IList Returns Null - WHY?

I have to miss something obvious here. I don't understand why this cast of linq query results returns null and not the list I'm querying.

IList<IMyDataInterface> list = query.ToList() as IList<IMyDataInterface>; 

The full code to run is given below. This is a knowledge gap that I need to bridge. I tried all kinds of permutations of the shots to make it work. I get no exceptions, just zero. It should be noted that the Linq query selects its results in instances of my custom "MyDataClass", which implements IMyDataInterface

 class Program { static void Main(string[] args) { IMyFunctionalInterface myObject = new MyClass(); //myObject.Get() returns null for some reason... IList<IMyDataInterface> list = myObject.Get(); Debug.Assert(list != null, "Cast List is null"); } } public interface IMyFunctionalInterface { IList<IMyDataInterface> Get(); } public class MyClass : IMyFunctionalInterface { public IList<IMyDataInterface> Get() { string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" }; var query = from n in names where n.Contains("a") select new MyDataClass { Name = n.ToString() }; //There IS data in the query result Debug.Assert(query != null, "result is null"); //but the cast here makes it return null IList<IMyDataInterface> list = query.ToList() as IList<IMyDataInterface>; return list; } } public interface IMyDataInterface { string Name { get; set; } } public class MyDataClass : IMyDataInterface { public string Name { get; set; } } 
+2
source share
2 answers

The problem here is one of covariance .

First, your example is too complex. I removed a little fluff. In addition, I have added some diagnostic tools that illuminate the problem.

 class Program { static void Main(string[] args) { var names = new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }; var query = from n in names select new C { S = n }; //There IS data in the query result Debug.Assert(query != null, "result is null"); //but the conversion here makes it return null var list = query.ToList() as IList<I>; Console.WriteLine(query.ToList().GetType()); // this assert fires. Debug.Assert(list != null, "Cast List is null"); } } interface I { string S { get; set; } } class C : I { public string S { get; set; } } 

The output of this program:

  System.Collections.Generic.List`1 [C]

Note that we are trying to use List<C> to List<I> , which does not work in C # 3.0.

In C # 4.0, you can do this thanks to a new joint and opposite dispersion of type parameters on common interfaces.

Also, your original question asked IQueryable , but that doesn't matter: the query expression you specified creates an IEnumerable<string> not a IQueryable<string> .

EDIT . I want to point out that your "cast" using the as operator is technically not great, but is a "type conversion". If you used cast, you would get an exception to the helpful information. If I go to:

  var list = (IList<I>)query.ToList(); 

I get an InvalidCastException with:

  Additional Information: Cannot start an object of type 'System.Collections.Generic.List 1[C]' to type 'System.Collections.Generic.IList 1 [I]'.
+13
source

Try the following:

 var query = from n in names where n.Contains("a") select new MyDataClass { Name = n.ToString() } as IMyDataInterface; 

Your problem in this line:

 IList<IMyDataInterface> list = query.ToList() as IList<IMyDataInterface>; 

It can also be written as:

 List<MyDataClass> tmp = query.ToList(); IList<IMyDataInterface> list = tmp as IList<IMyDataInterface>; 

Unfortunately, in C #, the as operator does not work the way you want it to. The as operator simply translates the list object as a list of another type; he does not try to go through the list and toss every item. To cast the list to something else, you need to call the Cast extension method. For instance:.

 IList<IMyDataInterface> list = query.ToList().Cast<IMyDataInterface>(); 

So, your options are: pour any element in your request as the interface you want (my first example), or give the whole list after the request is completed (my second example).

I suggest the first.

+5
source

Source: https://habr.com/ru/post/1306145/


All Articles