Linq - 向IList转换IQueryable返回null - 为什么? [英] Linq - Casting IQueryable to IList returns null - WHY?
问题描述
我必须在这里遗漏一些明显的东西。我不明白为什么这个linq查询结果的转换返回null而不是我正在请求的类型列表。
的IList< IMyDataInterface> list = query.ToList()as IList< IMyDataInterface> ;;
运行此命令的完整代码如下。这是我需要弥合的知识差距。我已经尝试过各种各样的演员阵容来让它发挥作用。我没有异常,只是一个空。值得注意的是,Linq查询将其结果选择为我的自定义MyDataClass实例,该实现IMyDataInterface
class Program
{
static void Main(string [] args)
{
IMyFunctionalInterface myObject = new MyClass();
//myObject.Get()由于某种原因返回null ...
IList< IMyDataInterface> list = myObject.Get();
Debug.Assert(list!= null,Cast List为null);
}
}
公共接口IMyFunctionalInterface
{
IList< IMyDataInterface>得到();
}
公共类MyClass:IMyFunctionalInterface
{
public IList< IMyDataInterface> Get()
{
string [] names = {Tom,Dick,Harry,Mary,Jay};
var query =来自名称中的n
其中n.Contains(a)
选择新的MyDataClass
{
Name = n.ToString( )
};
//查询结果中有IS数据
Debug.Assert(query!= null,result is null);
//但是这里的强制转换使它返回null
IList< IMyDataInterface> list = query.ToList()as IList< IMyDataInterface> ;;
返回清单;
}
}
公共接口IMyDataInterface
{
string Name {get;组; }
}
公共类MyDataClass:IMyDataInterface
{
public string Name {get;组; }
}
这里的问题是一个协方差。
首先,您的示例有点过于复杂。我已经删除了一些绒毛。此外,我添加了一些解决问题的诊断。
class Program
{
static void Main(string [] args)
{
var names = new [] {Tom,Dick,Harry,Mary,Jay};
var query = from name in names
select new C
{
S = n
};
//查询结果中有IS数据
Debug.Assert(query!= null,result is null);
//但这里的转换使得它返回null
var list = query.ToList()as IList< I> ;;
Console.WriteLine(query.ToList()。GetType());
//此断言触发。
Debug.Assert(list!= null,Cast List为null);
}
}
接口I
{
string S {get;组; }
}
class C:I
{
public string S {get;组; }
}
该程序的输出是:
System.Collections.Generic.List`1 [C]
请注意,我们正在尝试将列表< C>
转换为列表< I>
在C#3.0中不起作用。
在C#4.0中你应该能够做到这一点,这要归功于通用接口上类型参数的新的共同和反向差异。
此外,您的原始问题询问 IQueryable
,但这与此无关:您提供的查询表达式创建了 IEnumerable< string>
不是 IQueryable< string>
。
编辑:我想指出,使用作为
运算符的强制转换在技术上不是强制转换,而是类型转换 。如果您使用了演员表,那么您将获得有用信息的例外。如果我改为:
var list =(IList< I>)query.ToList();
我得到 InvalidCastException
with:
附加信息:无法转换类型为'System.Collections.Generic.List1 [C]的对象'输入'System.Collections.Generic.IList
1 [I]'。
I have to be missing something obvious here. I don't get why this cast of the results of a linq query returns null and not the typed list I'm requesting.
IList<IMyDataInterface> list = query.ToList() as IList<IMyDataInterface>;
The complete code to run this is below. This is a knowledge gap I need to bridge. I have tried all kinds of permutations of casts to get it to work. I get no Exceptions, just a null. Of note is that the Linq query is selecting its results into 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; }
}
The problem here is one of covariance.
First, your example is a bit too complicated. I have removed some fluff. Also, I've added some diagnostics 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 is:
System.Collections.Generic.List`1[C]
Note that we're trying to cast a List<C>
to List<I>
which doesn't work in C# 3.0.
In C# 4.0 you should be able to do this, thanks to the new co- and contra-variance of type parameters on generic interfaces.
Also, your original question asked about IQueryable
but that's not relevant here: the query expression you supplied creates an IEnumerable<string>
not an IQueryable<string>
.
EDIT: I want to point out that your "cast" using the as
operator is technically not a cast, but is a "type conversion". If you had use a cast, you would have gotten an exception with useful information. If I change to:
var list = (IList<I>)query.ToList();
I get an InvalidCastException
with:
Additional information: Unable to cast object of type 'System.Collections.Generic.List1[C]' to type 'System.Collections.Generic.IList
1[I]'.
这篇关于Linq - 向IList转换IQueryable返回null - 为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!