如何隐式地对我的自定义对象强制转换LINQ查询的结果?

时间:2016-09-23 15:19:04

标签: c# linq list collections casting

我正在开发一个使用大量自定义类的项目,每个自定义类都有效地表示来自数据库的一行数据。当有多个数据元素时,我一直在这样做:

public class Client
{
    private int _clientID;
    private double _annualRevenue;

    public int ClientID
    {
        get { return _clientID; }
        set { _clientID = value; }
    }

    public double AnnualRevenue
    {
        get { return _annualRevenue; }
        set { _annualRevenue = value; }
    }
}

然后,代码中的其他地方......

public class QueryClients
{

    private List<Client> _clients;

    public List<Client> FindClientByRevenue(double minimumRevenue)
    {
        List<Client> returnValue = (from c in _clients
                                    where c.AnnualRevenue >= minimumRevenue
                                    select c).ToList();

        return returnValue;
    }

}

这很好用,但恕我直言,要在代码中的其他地方继续声明这个列表是很难看的。我将不得不在至少100个不同的地方使用它。我想通过使用有意义的名称创建一个自定义类来简单地表示List,来清理它。我的意思是像这样的东西:

public class Clients : List<Client> { }

现在这个工作,但LINQ查询的结果不会强制转换为IMPLICITLY。所以忍受我。如果新代码看起来像这样......

public class QueryClients
{

    private Clients _clients;

    public QueryClients(Clients clients)
    {
        _clients = clients;
    }

    public Clients FindClientByRevenue(double minimumRevenue)
    {
        Clients returnValue = (from c in _clients
                                    where c.AnnualRevenue >= minimumRevenue
                                    select c).ToList();

        return returnValue;
    }

}

...我收到编译错误:

CS0266
Cannot implicitly convert type 'System.Collections.Generic.List<Client>' to 'Clients'. An explicit conversion exists (are you missing a cast?)  

好的,好的,所以我可以通过EXPLICITLY转换LINQ查询的结果来消除IDE中的编译器错误:

public class QueryClients
{

    private Clients _clients;

    public QueryClients(Clients clients)
    {
        _clients = clients;
    }

    public Clients FindClientByRevenue(double minimumRevenue)
    {
        Clients returnValue = (Clients)(from c in _clients
                                        where c.AnnualRevenue >= minimumRevenue
                                        select c).ToList();

        return returnValue;
    }

}

代码甚至编译得很好。但是一旦我点击那个查询,它就会爆炸。

        Clients clients = new Clients();
        Client client;

        client = new Client();
        client.ClientID = 1;
        client.AnnualRevenue = 100;
        clients.Add(client);

        client = new Client();
        client.ClientID = 2;
        client.AnnualRevenue = 200;
        clients.Add(client);

        client = new Client();
        client.ClientID = 3;
        client.AnnualRevenue = 300;
        clients.Add(client);

        QueryClients q = new QueryClients(clients);

        Clients clients2 = q.FindClientByRevenue(200);

当然,这是一个投射错误。

An unhandled exception of type 'System.InvalidCastException' occurred.

Additional information: Unable to cast object of type 'System.Collections.Generic.List`1[Client]' to type 'Clients'.

所以即使它编译,它也不会运行,即使这种方法DID工作,它也没有真正解决我的问题,因为那时我必须显式地转换每个LINQ查询的结果,如果我有要做到这一点,我不妨在任何地方宣布列表。叹息。

所以无论如何,我做错了什么,我只是看不出怎么做才能解决它。我确信,至少我需要在我的Clients类中添加某种转换/转换运算符,以允许隐式转换(或其他)。我根据众多不同的Google搜索尝试了很多不同的东西,它要么无法编译,要么无法运行。我只是想不出来。

有两个目标:

1。)在我的代码中使用Clients对象,而不是一遍又一遍地声明一个列表变量。

2.。)能够运行LINQ查询,从一个Clients对象中选择一些Client对象到另一个(新的)Clients对象。

这可能吗?你真的可以告诉我如何修改Clients类以便它可以工作(隐式地转换)吗?如果可以做到,我确信这很简单,我会在发布之前自己没有看过它。

提前感谢您的见解。

4 个答案:

答案 0 :(得分:1)

我道歉但改变了这一点:

public class QueryClients
{
    private List<Client> _clients;

    public List<Client> FindClientByRevenue(double minimumRevenue)
    {
        List<Client> returnValue = (from c in _clients
                                where c.AnnualRevenue >= minimumRevenue
                                select c).ToList();

        return returnValue;
    }
}

到此:

public class QueryClients
{
    private Clients _clients;

    public List<Client> FindClientByRevenue(double minimumRevenue)
    {
        Clients returnValue = (from c in _clients
                                where c.AnnualRevenue >= minimumRevenue
                                select c).ToList();

        return returnValue;
    }
}

没有意义。
您希望使用Clients类型与List<Client>完全相同 因此,如果您继续使用List<Client>通用List可以拥有的所有权益,那么似乎会更好。

答案 1 :(得分:1)

警告:不要这样做,坚持List<Client>,但出于教育原因,下面是答案

你有很多选择,首先是让你的类作为构造函数参数IEnumerable<Client>

public class Clients : List<Client>
{
    public Clients(IEnumerable<Client> clients) 
        : base(clients){}
}

然后作为您的查询

Clients returnValue = new Clients(from c in _clients
                                    where c.AnnualRevenue >= minimumRevenue
                                    select c);

另一种方法是提供一个明确的强制转换,以便在IList<Client>中执行相同操作,但您必须将Clients类更改为不继承List<Client>

public class Clients 
{
    private  List<Client> list;
    public Clients(IEnumerable<Client> clients) 
    { this.list = clients.ToList(); }

    public static explicit operator Clients(List<Client> list)
    {
          return new Clients(list);
    }
}

这会允许类似原始代码的内容

 Clients returnValue = (Clients)(from c in _clients
                                    where c.AnnualRevenue >= minimumRevenue
                                    select c).ToList();

答案 2 :(得分:0)

您应该创建一个链接到数据库的.dbml文件,您可以在该数据库中添加您希望模型类查询数据库的所有SQL表。这也将自动生成类,而无需编写任何代码。之后,您可以修改从数据库查询的此模型的实例并提交更改。没有一个SQL查询要写入更新或删除。一切都由LINQ处理。

这是一个很好的演练: https://msdn.microsoft.com/en-us/library/bb384428.aspx

一旦设置完毕,您所要做的就是: //创建DataContext

MyDataContext context = new MyDataContext(myConnectionString)

//查询一些客户端 - 客户端类将由LINQ

自动生成

列表&lt;客户&gt; clients =(来自客户端的context.Clients,其中CONDITON选择客户端).ToList()

//根据需要修改这些客户端 //提交对数据上下文的更改(将自动从此数据上下文更新已修改的类)

context.SubmitChanges()

答案 3 :(得分:-1)

你得到一个强制转换异常,因为列表查询结果的动态类型是List<Client>而不是从它继承的客户端(你不能从'动物'转换为'狗'对象实际上并不是“狗”。

由于您不能从基类进行任何用户定义的转换,我建议删除继承并添加隐式(或显式转换):

public class Clients {
    private List<Client> d;

    public Clients(List<Client> d)
    {
        this.d = d.ToList();
    }

    public static implicit operator Clients(List<Client> d)
    {
        return new Clients(d);
    }
}

然而,这不允许您将客户端视为可枚举。或者,您可以使用以下签名为IEnumerable<Client>编写扩展方法:

  public static Clients ToClientList(this IEnumerable<Client> input){
     return new Clients(input);
  } 

作为旁注,我认为使用List<Client>比定义自己的类更优雅和清晰..