почему я могу получить доступ только к свойствам анонимного типа, когда я добавляю .toList в конец моего запроса linq

Я изучаю LINQ и VB и просто потратил час, пытаясь получить доступ к полям анонимного типа, определенного в запросе linq. Ключ (я узнал) состоит в том, чтобы преобразовать запрос в список до, когда вы попытаетесь перебрать его с помощью цикла for. Как получить доступ к свойству анонимного типа в C #?

Это не работает: изменить (компилируется, но intellisense не распознает тип)

Dim varbl=from itm in collct select New With {.n=itm.Name} 'query here
for each returnedItem in varbl 
     returnedItem.n 'intellisense does not pick up the property names
next 

Но это действительно так:

Dim varbl=(from itm in collct select New With {.n=itm.Name}).toList
for each returnedItem in varbl 
     returnedItem.n 'this works
next 

Может кто-нибудь объяснить, почему / что происходит? Сообщение выше (иначе полезное!) Просто говорит: «Из-за того, как работает компилятор, следующее должно также работать после того, как вы создали список, потому что анонимные типы имеют одинаковую структуру, поэтому они также являются одним и тем же типом. У меня нет компилятора, чтобы проверить это "


person bernie2436    schedule 16.12.2011    source источник
comment
Это не отвечает на ваш вопрос, но если вы только начинаете, я настоятельно рекомендую вам изучить C # вместо VB. Вы найдете гораздо больше примеров кода и статей, которые могут вам помочь.   -  person danludwig    schedule 17.12.2011
comment
Я не знаю @olivehour, всегда кажется, что весь мир кодирует C #, кроме парня, который пишет учебник в Интернете где-то по тому, о чем я хочу знать :)   -  person Jon Hanna    schedule 17.12.2011


Ответы (1)


Что ж, я не собирался отвечать, так как мой VB и очень ржавый, и довольно устаревший (ага, VB6 около десяти лет назад). Но что-то здесь показалось неправильным с точки зрения .NET.

Ваше чтение ответа, на который вы ссылаетесь (который является неполным в своем объяснении, IMO), неверно. Дело не в том, что вам нужно поместить анонимный объект в список, а в том, что кверент там помещал его в List<object>, что означало, что компилятор не мог определить, какие свойства у него были (он имеет дело с object, а не с объектом рассматриваемый анонимный тип, и object не имеет свойства Checked).

В любом случае. Я попытался написать вашу первоначальную попытку на каком-то C # как:

private class TestType
{
  public string Name{get;set;}
  public TestType(string name)
  {
    this.Name = name;
  }
}
public static void Main()
{
  TestType[] collct = new TestType[]{new TestType("abc"), new TestType("def"), new TestType("xyz")};
  var varbl = from itm in collct select new {n = itm.Name};
  foreach(var returnedItem in varbl)
    Console.WriteLine(returnedItem.n);
}

Затем я скомпилировал и декомпилировал как VB.NET в отражателе, в котором мой Main был следующим:

Public Shared Sub Main()
    Dim collct As TestType() = New TestType() { New TestType("abc"), New TestType("def"), New TestType("xyz") }
    Dim varbl = (From itm In collct Select New With { _
        .n = itm.Name _
    })
    Dim returnedItem
    For Each returnedItem In varbl
        Console.WriteLine(returnedItem.n)
    Next
End Sub

Что очень похоже на ваш оригинал, не так ли?

Что ж, это работает; он компилируется и запускается и дает мне правильные ответы.

Единственное, о чем я могу думать, это то, что, возможно, IntelliSense здесь просто не на высоте. Я обнаружил, что несколько раз в прошлом IntelliSense изо всех сил пытается предложить имена свойств анонимных типов, и хотя я использую SharpDevelop для кодирования C #, а не VB (в любой IDE, которую вы используете), это может иметь место здесь - у вас действительно был правильный код, но IntelliSense этого не осознавал.

В конце концов, IntelliSense чертовски хорош, но это не компилятор, и он не может тратить столько ресурсов на выполнение каких-либо задач, как компилятор, из-за риска замедлить нас, пока мы печатаем.

Между прочим, вам не следует не вызывать ToList, если вам действительно не нужен список для ваших целей. Представьте, если бы collct был перечислением, загружаемым по мере необходимости, которое возвращало бы тысячи объектов после загрузки чего-либо из базы данных или файла.

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

Если вы вызовете ToList, программа застрянет на этой строке до тех пор, пока не загрузит каждый отдельный объект в массивный список в памяти, и только после этого запустит ваш For Each.

Конечно, бывают случаи, когда вам действительно нужно иметь возможность перемещаться вперед и назад по списку или знать счетчик перед повторением, и тогда, безусловно, лучше позвонить ToList, чем продолжать повторять For Each, но если вы этого не сделаете не знаете, что вам это нужно, не используйте это.

person Jon Hanna    schedule 16.12.2011
comment
Привет, Джон. Спасибо за Ваш ответ. Я удалил .toList, и код скомпилировал и работал нормально. Думаю, вы были правы: это был тот случай, когда intellisense оказался не таким умным, как компилятор. Просто b / c intelsense не распознал тип, это не означало, что компилятор тоже не распознал бы тип. По-видимому (как вы, вероятно, знаете) в C # ключевое слово Var содержит переменную, тип которой не присваивается до тех пор, пока код не будет скомпилирован. Я предполагаю, что Dim от VB работает точно так же. может быть, как-то добавить toList 'preassigned' типа? В любом случае, для noob ключ в том, что intellsense не является компилятором - person bernie2436; 19.12.2011
comment
Хех, новичок, который узнает, что делает лучше, чем некоторые опытные пользователи. И даже действительно опытные пользователи (с многолетним опытом, а не с многолетним опытом) могут смущаться, когда IntelliSense внезапно что-то не улавливает. - person Jon Hanna; 19.12.2011
comment
Однако в этом отношении переменные, типизированные компилятором (var в C #, Dim без As и с Option Infer On), обычно подбираются IntelliSense. Просто иногда он не работает или работает не полностью. - person Jon Hanna; 19.12.2011