Объявление неявно типизированной переменной внутри условной области видимости и ее использование вне

В упрощенном коде ниже

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?


person FMFF    schedule 05.01.2012    source источник
comment
Я полагаю, вы могли бы объявить переменную вне блоков.   -  person ChaosPandion    schedule 06.01.2012
comment
Я получаю, что неявно типизированные локальные переменные должны быть инициализированы   -  person FMFF    schedule 06.01.2012
comment
Под x.* вы имеете в виду построение анонимного типа, верно? Если нет, то почему вы настаиваете на неявной типизации?   -  person CodesInChaos    schedule 06.01.2012
comment
Да, я имел в виду анонимный тип, когда писал x. *. Итак, в моем фактическом коде выбор выглядит как select new {columnA, columnB, columnC}. Извините за упрощение.   -  person FMFF    schedule 06.01.2012
comment
В этом случае, поскольку условный блок используется только для изменения предложения where запроса LINQ, вы можете избежать всей проблемы: удалить блок if и изменить предложение where на where x.CostOfLiving == ((city == "New York City") ? "VERY HIGH" : "MODERATE"). В более сложном случае замените предложение where соответствующим универсальным предикатом ...   -  person Dan J    schedule 06.01.2012
comment
Я по глупости забыл упомянуть, что WHERE будет отсутствовать в моей else части. Вместо того, чтобы редактировать код, я оставляю его для контекста. В любом случае предложение Эрика сработало для меня. Спасибо, SOF.   -  person FMFF    schedule 06.01.2012


Ответы (6)


Поясним ваш запутанный вопрос. Проблема в том, что у вас есть две локальные переменные, каждая из которых имеет один и тот же «невыразимый» тип - последовательность анонимного типа.

Я бы изменил ваш конкретный код следующим образом:

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 = ...

Это разновидность трюка, называемого «приведение по примеру», где вы даете пример анонимного типа универсальному методу. Затем вывод типа метода определяет, что такое возвращаемый тип, и использует его как тип неявно типизированного локального. Во время выполнения он ничего не делает, кроме создания бесполезного объекта, который затем быстро отбрасывается.

person Eric Lippert    schedule 06.01.2012
comment
Это, без сомнения, самый умный трюк, который я видел за весь год. - person Polynomial; 10.10.2012

Если вы используете именованный тип, просто объявите переменную с этим типом перед 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});

Or:

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

Какой из них подходит, зависит от того, насколько вы упростили свой вопрос.

person CodesInChaos    schedule 05.01.2012

Попробуй это:

var ret = default(object);
person user3006492    schedule 19.11.2013

попробуй это:

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>");
}
person Raoof Arakkal    schedule 14.11.2012

Вам нужно будет объявить переменную вне области действия оператора if, чтобы использовать ее в цикле foreach.

Если переменная объявлена, но не инициализирована вне оператора if, она не может быть типизирована неявно, потому что у компилятора не будет выражения для определения типа.

Если он будет использоваться только в цикле foreach, вы можете объявить его как IEnumerable.

person Andrew Kennan    schedule 05.01.2012

вам нужно будет определить MyObject как var перед условием:

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.*;

}
person Hassan Gulzar    schedule 05.01.2012
comment
В дополнительном мертвом запросе нет необходимости. Просто напишите фактический тип. - person ChaosPandion; 06.01.2012
comment
@ChaosPandion Я предполагаю, что это анонимный тип. - person CodesInChaos; 06.01.2012