Linq - 向IList转换IQueryable返回null - 为什么? [英] Linq - Casting IQueryable to IList returns null - WHY?

查看:157
本文介绍了Linq - 向IList转换IQueryable返回null - 为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须在这里遗漏一些明显的东西。我不明白为什么这个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.List 1 [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.IList1[I]'.

这篇关于Linq - 向IList转换IQueryable返回null - 为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆