【问题标题】:Creating an anonymous type depending on different conditions and casting it to a class根据不同的条件创建匿名类型并将其强制转换为类
【发布时间】:2015-05-22 11:30:37
【问题描述】:

我现在有这个问题,但今天我达到了临界点,我正在寻求您的帮助。

假设我有这个代码:

var query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
    // Do the work
}

我最终得到了这种匿名类型,一切都很好。现在出现了一些让我对 Where 子句进行条件化的事情,所以我必须根据条件进行不同的查询,这就是我真正感到沮丧的地方:

if(something)
{
    var query = DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c });
    foreach(var item in query)
    {
        // Do the work
    }
}
else
{
    var query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
    foreach(var item in query)
    {
        // Do the work
    }
}

因为foreach循环中要做的工作完全一样,我不应该重复。

所以,我没有使用匿名类型,而是声明了一个新类并尝试了这个:

class MyQuery
{
    public int a { get; set; }
    public string b { get; set; }
    public decimal? c { get; set; }
}

IQueryable<MyQuery> query = null;

if(something)
{
    query = (IQueryable<MyQuery>)DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c });
}
else
{
    query = (IQueryable<MyQuery>)DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
}

foreach(var item in query)
{
    // Do the work
}

但是现在我抛出了一个'System.InvalidCastException',因为我仍然得到一个匿名类型,显然它不能被强制转换到我的类中。

为了维护,我想避免重复代码,但我不知道该怎么做。我觉得我在这里缺少一些基本的东西,但找不到什么,所以欢迎和感谢您的帮助。

非常感谢您的帮助。

【问题讨论】:

  • 你的第二个代码仍然可以使用匿名类(只需删除演员表)。唯一需要自定义类的情况是当您想要将数据传入或传出方法时。

标签: c# lambda anonymous-types


【解决方案1】:

你太复杂了:

IQueryable<MyQuery> query = DbContext.Table;

if (something)
{
    query = query.Where(x => x.z == true && x.zz == false)
}
else
{
    query = query.Where(x => x.z == true);
}

var result = query.Select(x => new { x.a, x.b, x.c });

foreach (var item in result)
{
    // Do the work
}

.Where() 方法不会改变查询的“类型”!

请注意,即使这是合法的:

var query = DbContext.Table.Select(x => new { x.a, x.b, x.c });

if (something)
{
    query = DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c });
}
else
{
    query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c });
}

foreach (var item in query)
{
    // Do the work
}

我正在使用这样一个事实,即在同一程序集中具有相同参数(参数名称相同、参数类型相同、参数数量相同)的匿名类型由 C# 编译器“统一”。我使用这一行var query = DbContext.Table.Select(x =&gt; new { x.a, x.b, x.c }); 仅将类型“赋予”给var 变量。然后我用其他查询完全覆盖查询,因为各种.Select(x =&gt; new { x.a, x.b, x.c });“产生”相同(匿名)类型的对象。

【讨论】:

  • 是的,我过于复杂了。这是我所缺少的基本内容。非常感谢。
【解决方案2】:

您可以修改Where 条件以匹配一个案例或另一个。这样,您不再需要担心重复代码或创建仅用于此方法的另一个类。

var query = DbContext.Table.Where(x => something && (x.z == true && x.zz == false) || !something && (x.z == true)).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
    // Do the work
}

或者您可以添加一个三元比较@Rawling 提到的方式。

var query = DbContext.Table.Where(x => something ? (x.z == true && x.zz == false) : (x.z == true)).Select(x => new { x.a, x.b, x.c });
foreach(var item in query)
{
    // Do the work
}

【讨论】:

  • @adricar 请注意,有时 SQL 的查询编译器/优化器可能会因where 的“死”片段而“脱轨”...
  • 我觉得x =&gt; something ? (x.z == true &amp;&amp; x.zz == false) : (x.z == true)在这里更清晰。
  • @Rawling 你是个天才 :D,这看起来更好
猜你喜欢
  • 2011-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多