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

本文关键字:转换 LINQ 查询 结果 自定义 对象 | 更新日期: 2023-09-27 18:08:26

我正在处理一个使用大量自定义类的项目,每个类都有效地表示来自数据库的一行数据。当有不止一个数据元素时我就会这样做:

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查询的结果不会隐式地强制转换给它。请耐心听我说。如果新代码看起来像这样…

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?)  

好了,好了,所以我可以通过显式转换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'.

所以即使它编译,它不会运行,即使这种方法确实工作,它并没有真正解决我的问题,因为这样我就必须显式地转换每个LINQ查询的结果,如果我必须这样做,我也可以到处声明列表。叹息。

所以,无论如何,我做错了什么,我只是不知道如何去解决它。我确信,至少,我需要向我的Clients类添加某种类型的转换/强制转换操作符,以允许发生隐式转换(或其他)。我已经尝试了许多不同的东西基于许多不同的谷歌搜索,它要么不会编译,要么不会运行。我就是想不明白。

有两个目标:

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

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

这可能吗?你能告诉我如何修改Clients类使其工作吗(隐式强制转换)?如果可以做到,我肯定它很简单,我会责备自己在发布之前没有亲自看过。

谢谢你的建议。

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

我很抱歉,但改变这个:

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;
    }
}

没有意义。
您期望以与List<Client>完全相同的方式使用类型Clients
所以如果你继续使用List<Client>似乎更好,List可以有所有的好处。

警告:不要这样做,坚持使用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();

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

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

一旦一切都设置好了,你要做的就是://创建DataContext

MyDataContext context = new MyDataContext(myConnectionString)

//查询一些客户端-客户端类将由LINQ自动生成

列表& lt;Client> clients = (from Client in context)select client).ToList()

//修改客户端//向数据上下文提交更改(将自动从该数据上下文更新修改过的类)

context.SubmitChanges ()

你得到一个cast异常,因为列表查询结果的动态类型是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>比定义自己的类更优雅,更清晰。