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

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

Это не работает: edit (компилируется, но 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 

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

1 Ответ

2 голосов
/ 17 декабря 2011

Ну, я не собирался отвечать, так как мой 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, но если вы не знаете , вам это нужно, не делайтене используй его.

...