我必须在这里遗漏一些明显的东西。我不明白为什么这个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() 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; }
}
答案 0 :(得分:13)
此处的问题是协方差之一。
首先,你的例子有点太复杂了。我已经删除了一些绒毛。另外,我添加了一些可以解决问题的诊断信息。
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; }
}
该程序的输出是:
System.Collections.Generic.List`1[C]
请注意,我们正在尝试将List<C>
转换为List<I>
,这在C#3.0中无效。
在C#4.0中,你应该能够做到这一点,这要归功于通用接口上类型参数的新的共同和反差。
此外,您的原始问题询问IQueryable
,但这与此处不相关:您提供的查询表达式会创建IEnumerable<string>
而不是IQueryable<string>
。
编辑:我想指出,使用as
运算符的“强制转换”在技术上不是强制转换,而是“类型转换”。如果您使用了演员表,那么您将获得有用信息的例外。如果我改为:
var list = (IList<I>)query.ToList();
我得到了InvalidCastException
:
Additional information: Unable to cast object of type 'System.Collections.Generic.List1[C]' to type 'System.Collections.Generic.IList
1[I]'.
答案 1 :(得分:5)
试试这个:
var query = from n in names
where n.Contains("a")
select new MyDataClass
{
Name = n.ToString()
} as IMyDataInterface;
你的问题在这一行:
IList<IMyDataInterface> list = query.ToList() as IList<IMyDataInterface>;
这也可以写成:
List<MyDataClass> tmp = query.ToList();
IList<IMyDataInterface> list = tmp as IList<IMyDataInterface>;
不幸的是,在C#中,as
运算符无法以您希望的方式运行。 as
运算符只是将列表对象强制转换为不同类型的列表;它不会尝试通过列表并投射每个项目。要将列表转换为其他内容,您需要在其上调用Cast扩展方法。 E.g:
IList<IMyDataInterface> list = query.ToList().Cast<IMyDataInterface>();
因此,您的选项是:在您的查询中将所有项目作为您想要的界面(我的第一个示例)投射,或者在执行查询后投射整个列表(我的第二个示例)。
我建议前者。