Я играл с некоторыми образцами linq, поставляемыми с LINQPad.В папке «C # 3.0 в двух словах» в главе 9 «Группировка» приведен пример запроса под названием «Группировка по нескольким ключам».Он содержит следующий запрос:
from n in new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable()
group n by new
{
FirstLetter = n[0],
Length = n.Length
}
Я добавил строку «Jon» в конец массива для получения фактической группировки и получил следующий результат:
Это было именно то, что я ожидал.Затем в LINQPad я перешел к версии VB.NET того же запроса:
' Manually added "Jon"
from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _
group by ng = new with _
{ _
.FirstLetter = n(0), _
.Length = n.Length _
} into group
В результате неправильно сгруппированы Jay / Jon.
Немного потянув за волосы, я обнаружил эту статью MSDN , в которой обсуждаются анонимные типы VB.NET.В VB.NET они изменяемы по умолчанию, в отличие от C #, где они неизменны.В VB вам нужно добавить ключевое слово Key
, чтобы сделать их неизменяемыми.Итак, я изменил запрос на это (обратите внимание на добавление Key
):
from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _
group by ng = new with _
{ _
Key .FirstLetter = n(0), _
Key .Length = n.Length _
} into group
Это дало мне правильный результат:
Итаку меня такой вопрос:
- Почему изменчивость / неизменность анонимных типов имеет значение, когда linq выполняет сравнение на равенство?Примечательно, что в Linq-to-SQL это вообще не имеет значения, что, вероятно, является просто продуктом перевода в SQL.Но в Linq-to-objects это, по-видимому, имеет все значение.
- Почему MS решила сделать изменяемые анонимные типы VB.Я не вижу никакого реального преимущества, и после осмотра этой проблемы я вижу некоторые очень реальные недостатки.А именно, что ваши запросы linq могут иметь незначительные ошибки.
- EDIT -
Просто интересная дополнительная часть информации ... По-видимому, эта проблема ключевого свойства широко известна.Я просто не знал, для чего Google.Это обсуждалось здесь и здесь в стеке потока.Вот еще один пример проблемы с использованием анонимных типов и Distinct:
Dim items = New String() {"a", "b", "b", "c", "c", "c"}
Dim result = items.Select(Function(x) New With {.MyValue = x}).Distinct()
Dim result2 = items.Select(Function(x) New With {Key .MyValue = x}).Distinct()
'Debug.Assert(result.Count() = 3) ' Nope... it's 6!
Debug.Assert(result2.Count() = 3)