Це загальна форма (як це вже передбачено в інших відповідях)
var c =
from a in alpha
join b in beta on b.field1 equals a.field1 into b_temp
from b_value in b_temp.DefaultIfEmpty()
select new { Alpha = a, Beta = b_value };
Однак ось пояснення, яке, сподіваюся, з’ясує, що це насправді означає!
join b in beta on b.field1 equals a.field1 into b_temp
по суті створює окремий набір результатів b_temp, який фактично включає нульові "рядки" для записів у правій частині (записи в "b").
Потім наступний рядок:
from b_value in b_temp.DefaultIfEmpty()
..позначає цей набір результатів, встановлюючи значення за замовчуванням для "рядка" з правого боку та встановлюючи результат приєднання рядка правого боку до значення "b_value" (тобто значення, яке знаходиться праворуч сторона, якщо є відповідна запис, або "null", якщо її немає).
Тепер, якщо правий бік є результатом окремого запиту LINQ, він буде складатися з анонімних типів, який може бути або "щось", або "нульовим". Якщо це незліченна кількість (наприклад, Список - де MyObjectB - клас з двома полями), то можна визначити, які значення "null" за замовчуванням використовуються для його властивостей:
var c =
from a in alpha
join b in beta on b.field1 equals a.field1 into b_temp
from b_value in b_temp.DefaultIfEmpty( new MyObjectB { Field1 = String.Empty, Field2 = (DateTime?) null })
select new { Alpha = a, Beta_field1 = b_value.Field1, Beta_field2 = b_value.Field2 };
Це гарантує, що 'b' сам по собі не є нульовим (але його властивості можуть бути нульовими, використовуючи вказані вами значення за замовчуванням, які ви вказали), і це дозволяє перевірити властивості b_value, не отримуючи нульового опорного винятку для b_value. Зауважте, що для зведеного DateTime тип (DateTime?), Тобто "зведений DateTime", повинен бути вказаний як "Тип" нуля в специфікації для "DefaultIfEmpty" (це стосується також типів, які не є "спочатку" 'мінливий, наприклад, подвійний, плаваючий).
Ви можете виконати кілька лівих зовнішніх приєднань, просто прив’язавши вищевказаний синтаксис.