在条件范围内声明一个隐式类型变量并在外部使用它

5
在下面的简化代码中,
if(city == "New York City")
{
  var MyObject = from x in MyEFTable
                     where x.CostOfLiving == "VERY HIGH"
                     select x.*;

}
else
{
  var MyObject = from x in MyEFTable
                     where x.CostOfLiving == "MODERATE"
                     select x.*;

}

  foreach (var item in MyObject)
  {
     Console.WriteLine("<item's details>");
  }

变量MyObject在条件块外不可访问。我该如何在if..else之外进行迭代?

我想你可以在代码块之外声明变量。 - ChaosPandion
1
我得到了"隐式类型的局部变量必须被初始化"。 - FMFF
1
你说的 x.* 是指匿名类型的构造吗?如果不是,为什么要坚持隐式类型声明呢? - CodesInChaos
是的,当我写 x.* 时,我指的是匿名类型。所以在我的实际代码中,select 语句看起来像 select new {columnA, columnB, columnC}。对于过分简化的描述,我感到抱歉。 - FMFF
3
在这种情况下,由于条件块仅用于修改LINQ查询的'where'子句,因此您可以避免整个问题:消除'if'块并将'where'子句更改为'where x.CostOfLiving == ((city ==“New York City”)?“VERY HIGH”:“MODERATE”)'。在更复杂的情况下,请使用适当的通用谓词替换'where'子句... - Dan J
我愚蠢地忘记提到的是,在我的“else”部分中将缺少“WHERE”。我没有编辑代码,而是留下了它作为上下文。无论如何,Eric的建议对我很有用。谢谢SOF。 - FMFF
7个回答

24

让我们澄清您困惑的问题。问题在于您有两个本地变量,每个变量都具有相同的“难以言喻”的类型--一个匿名类型的序列。

我会像这样更改您特定的代码:

string cost = city == "NYC" ? "HIGH" : "MODERATE";
var query = from row in table 
            where row.Cost == cost 
            select new { row.Population, row.Elevation };

然而,如果出于某种原因您仍需要保持代码结构不变,可以这样做:
static IEnumerable<T> SequenceByExample<T>(T t){ return null; }
...
var query = SequenceByExample(new { Population = 0, Elevation = 0.0 } );
if (whatever)
    query = ...
else
    query = ...

这是一种称为“按示例转换”的技巧变体,您将匿名类型的示例提供给通用方法。然后,方法类型推断确定返回类型,并将其用作隐式类型局部变量的类型。运行时,它仅创建一个无用的对象,然后快速丢弃它。

3
毫无疑问,这是我今年看过的最聪明的把戏。 - Polynomial

4

如果您正在使用已命名的类型,请在if之前声明一个该类型的变量,但这种情况就会变得平凡无奇。

因此,我假设您正在选择匿名类型,因此无法显式地声明该类型的变量。

通过示例进行转换也可以解决问题。但这不像是一个好的解决方案。可能创建一个命名类型是一个更好的想法。

var myObject =Enumerable.Empty<RowType>.Select(row=>select new {columnA, columnB, columnC});
if(city == "New York City")
{
  myObject= from x in MyEFTable
                     where x.CostOfLiving == "VERY HIGH"
                     select select new {columnA, columnB, columnC};
}
else
{
  myObject = from x in MyEFTable
                     where x.CostOfLiving == "MODERATE"
                     select select new {columnA, columnB, columnC};
}

在您具体的示例中,可以仅在条件语句之后进行投影:

IQueryable<RowType> partialQuery;
if(city == "New York City")
    partialQuery=MyEFTable.Where(x=>x.x.CostOfLiving == "VERY HIGH");
else
    partialQuery=MyEFTable.Where(x=>x.x.CostOfLiving == "MODERATE");
var myObject=partialQuery.Select(x=>x.new {columnA, columnB, columnC});

或者:

Expression<Predicate<RowType>> filter;//Note that this is an Expression, not just a delegate
if(city == "New York City")
  filter=x=>x.x.CostOfLiving == "VERY HIGH";
else
  filter=x=>x.x.CostOfLiving == "MODERATE";
var myObject=MyEFTable.Where(filter).Select(x=>x.new {columnA, columnB, columnC});

甚至只是这样:
string s;
if(city == "New York City")
  s="VERY HIGH";
else
  s="MODERATE";
var myObject=MyEFTable.Where(x=>x.CostOfLiving == s).Select(x=>x.new {columnA, columnB, columnC});

哪一种适合取决于您如何简化问题。

3

试试这个:

var ret = default(object);

2

试试这个:

System.Linq.IQueryable<MyEFTable Object type> MyObject = null;
if(city == "New York City")
{
  MyObject = from x in MyEFTable
             where x.CostOfLiving == "VERY HIGH"
             select x.*;
}
else
{
  MyObject = from x in MyEFTable
             where x.CostOfLiving == "MODERATE"
             select x.*;
}

foreach (var item in MyObject)
{
  Console.WriteLine("<item's details>");
}

1
你需要在 if 语句的范围之外声明变量,以便在 foreach 循环中使用它。
如果变量在 if 语句之外被声明但未初始化,则无法隐式地为其分配类型,因为编译器无法从表达式中确定类型。
如果只会在 foreach 循环中使用它,可以将其声明为 IEnumerable。

1
List<MyObject> list = null; 

if(city == "New York City")    
   list = (from x in MyEFTable  where x.CostOfLiving == "VERY HIGH"
                     select x.*).ToList();       
else    
   list = (from x in MyEFTable where x.CostOfLiving == "MODERATE"
                     select x.*).ToList();        

foreach (var item in list)   
     Console.WriteLine("<item's details>");    

0

在条件语句之前,你需要将MyObject定义为一个变量:

var MyObject = from x in MyEFTable
                     where x.CostOfLiving == "SOMETHING THAT'LL RETURN NO ROWS"
                     select x.*;

这将为MyObject变量分配一个模式。

现在,您可以按照以下条件继续进行:

if(city == "New York City")
{
  MyObject = from x in MyEFTable
                     where x.CostOfLiving == "VERY HIGH"
                     select x.*;

}
else
{
  MyObject = from x in MyEFTable
                     where x.CostOfLiving == "MODERATE"
                     select x.*;

}

2
多余的死查询是不必要的。只需写出实际类型即可。 - ChaosPandion
@ChaosPandion 我假设这个类型是匿名的。 - CodesInChaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接