主頁 > .NET開發 > C#.NET 強大的LINQ

C#.NET 強大的LINQ

2020-11-04 19:06:34 .NET開發

LINQ 是 Language INtegrated Query 單詞的首字母縮寫,翻譯過來是語言集成查詢,它為查詢跨各種資料源和格式的資料提供了一致的模型,所以叫集成查詢,由于這種查詢并沒有制造新的語言而只是在現有的語言基礎上來實作,所以叫語言集成查詢,

基礎

從功能上 LINQ 可分為兩類:
  • LINQ to Object,查詢記憶體集合,直接把查詢編譯成 .NET 代碼執行,
  • LINQ to Provider,查詢自定義資料源,由開發者提供相應資料源的 Provider 并翻譯和執行自定義查詢,如 XML、JSON 等都可以作為 Provider 對應的資料源,資料源對應的 LINQ 查詢叫 LINQ to <資料源>,比如:LINQ to XML,
從語法上 LINQ 可以分為:
  • SQL風格:語法和 SQL 相似,部分復雜查詢用 SQL 風格語意會更清晰明了,比如 SelectMany 和 Join 查詢,SQL 風格的可讀性有絕對優勢,但不支持全部標準 LINQ 函式,不支持自定義函式,純粹的語法糖,
  • 函式風格:以 C# 擴展方法的方式實作,擴展方法即可以是標準庫提供的也可以是自己實作的,完全的原生編程風格,編譯后的代碼都是函式呼叫,支持全部標準 LINQ 函式和任何自定義函式,隨著查詢復雜度的提高,可讀性不如 SQL 風格,

LINQ to Object 多用于映射資料庫的查詢,LINQ to XML 用于查詢 XML 元素資料,使用 LINQ 查詢的前提是物件必須是一個 IEnumerable 集合(注意,為了描述方便,本文說的集合都是指 IEnumerable 物件,包含字面上的 ICollection 物件),另外,LINQ 查詢大多是都是鏈式查詢,即操作的資料源是 IEnumerable<T1> 型別,回傳的是 IEnumerable<T2> 型別,

形如下面這樣的查詢就是 LINQ to Object:

var list = from user in users
where user.Name.Contains("Wang")
select user.Id;

等同于使用下面的 LINQ 擴展方法:

var list = users
.Where(u => user.Name.Contains("Wang"))
.Select(u => u.id);

LINQ 查詢支持在陳述句中間根據需要定義變數,比如取出陣列中平方值大于平均值的數字:

int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = from number in numbers
let average = numbers.Average()
let squared = Math.Pow(number, 2)
where squared > average
select number;
// 平均值為 4.5, result 為 { 3, 4, 5, 6, 7, 8, 9 }

其中的 Select 方法接收的引數用的最多的是 Func<TSource, TResult>,它還可以接收 Func<TSource, int, TResult> 引數,示例:

var collectionWithRowNumber = collection.
.Select((item, index) => new { Item = item, RowNumber =index })
.ToList();

再來看一下 LINQ to XML 的示例,假如我們有如下 XML 檔案:

<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<EmpId>1</EmpId>
<Name>Liam</Name>
<Sex></Sex>
</Employee>
<Employee>
<EmpId>2</EmpId>
...
</Employee>
</Employees>

使用 LINQ to XML 查詢所有含有指定節點值的元素:

XElement xelement = XElement.Load("Employees.xml");
var els = from el in xelement.Elements("Employee")
where (string)el.Element("Sex") == "Male"
select el;

等同于使用 LINQ 擴展方法:

var els = xelement.Elements("Employee")
.Where(el => (string)el.Element("Sex") == "Male");

LINQ to XML 操作 XML 非常方便和靈活,大家可以在具體使用的時候去探索,這里就不展開講了,

LINQ 查詢有很多方法,由于篇幅原因,就不一一列舉演示了,這里只選取一些強大的查詢方法,這些方法若使用非 LINQ 來實作可能會比較麻煩,

LINQ 之所以強大,是因為它可以輕松實作復雜的查詢,下面我們來總結一下 C# LINQ 的強大之處,

First、Last 和 Single 等

First、FirstOrDefault、Last、LastOrDefault、Single 和 SingleOrDefault 是快速查詢集合中的第一個或最后一個元素的方法,如果集合是空的,Fist、Last 和 Single 都會報錯,如果使其不報錯而在空集合時使用默認值可以使用 FirstOrDefault、LastOrDefault 和 SingleOrDefault,Single/SingleOrDefault 和其它方法的區別是,它限定查詢結果只有一個元素,如果查詢結果集合中包含多個元素時會報錯,具體看下面幾個示例:

new[] { "a", "b" }.First(x => x.Equals("b")); // 回傳 ”b“
new[] { "a", "b" }.First(x => x.Equals("c")); // 拋出 InvalidOperationException 例外
new[] { "a", "b" }.FirstOrDefault(x => x.Equals("c")); // 回傳 null

new[] { "a", "b" }.Single(x => x.Equals("b")); // 回傳 ”b“
new[] { "a", "b" }.Single(x => x.Equals("c")); // 拋出 InvalidOperationException 例外
new[] { "a", "b" }.SingleOrDefault(x => x.Equals("c")); // 回傳 null
new[] { "a", "a" }.Single(); // 拋出 InvalidOperationException 例外

在實際應用中,如果要確保查詢結果的唯一性(比如通過手機號查詢用戶),使用 Single/SingleOrDefaut,其它情況應盡量使用 First/FirstOrDefault,雖然 FirstOrDefault 也可以根據條件判斷元素是否存在,但使用 Any 更高效,

Except 取差集

LINQ 的 Except 方法用來取差集,即取出集合中與另一個集合所有元素不同的元素,

示例:

int[] first = { 1, 2, 3, 4 };
int[] second = { 0, 2, 3, 5 };
IEnumerable<int> result = first.Except(second);
// result = { 1, 4 }

注意 Except 方法會去除重復元素:

int[] second = { 0, 2, 3, 5 };
int[] third = { 1, 1, 1, 2, 3, 4 };
IEnumerable<int> result = third.Except(second);
// result = { 1, 4 }

對于簡單型別(int、float、string 等)使用 Except 很簡單,但對于自定義型別(或者叫復合型別,下同)的 Object 如何使用 Except 呢?此時需要將自定義型別實作IEquatable<T>介面,示例:

class User : IEquatable<User>
{
public string Name { get; set; }

public bool Equals(User other)
{
return Name == other.Name;
}

public override int GetHashCode()
{
return Name?.GetHashCode() ?? 0;
}
}

class Program
{
static void Main(string[] args)
{
var list1 = new List<User>
{
new User{ Name = "User1"},
new User{ Name = "User2"},
};

var list2 = new List<User>
{
new User{ Name = "User2"},
new User{ Name = "User3"},
};

var result = list1.Except(list2);
result.ForEach(u => Console.WriteLine(u.Name));
// 輸出:User1
}
}

SelectMany 集合降維

SelectMany 可以把多維集合降維,比如把二維的集合平鋪成一個一維的集合,舉例:

var collection = new int[][]
{
new int[] {1, 2, 3},
new int[] {4, 5, 6},
};
var result = collection.SelectMany(x => x);
// result = [1, 2, 3, 4, 5, 6]

再來舉個更貼合實際應用的例子,例如有如下物體類(一個部門有多個員工):

class Department
{
public Employee[] Employees { get; set; }
}

class Employee
{
public string Name { get; set; }
}

此時,我們擁有一個這樣的資料集合:

var departments = new[]
{
new Department()
{
Employees = new []
{
new Employee { Name = "Bob" },
new Employee { Name = "Jack" }
}
},
new Department()
{
Employees = new []
{
new Employee { Name = "Jim" },
new Employee { Name = "John" }
}
}
};

現在我們可以使用 SelectMany 把各部門的員工查詢到一個結果集中:

var allEmployees = departments.SelectMany(x => x.Employees);
foreach(var emp in allEmployees)
{
Console.WriteLine(emp.Name);
}
// 依次輸出:Bob Jack Jim John

SelectMany 迪卡爾積運算

SelectMany 不光適用于單個包含多維集合物件的降維,也適用于多個集合之前的兩兩相互操作,比如進行迪卡爾積運算,比如我們有這樣兩個集合:

var list1 = new List<string> { "a1", "a2" };
var list2 = new List<string> { "b1", "b2", "b3" };

現在我們需要把它進行兩兩組合,使用普通的方法,我們需要用嵌套回圈陳述句來實作:

var result = newList<string>();
foreach (var s1 in list1)
foreach (var s2 in list2)
result.Add($"{s1}{s2}");
// result = ["a1b1", "a1b2", "a1b3", "a2b1", "a2b2", "a2b3"]

改用 SelectMany 實作:

var result = list1.SelectMany(x => list2.Select(y => $"{x}{y}"));
// result = ["a1b1", "a1b2", "a1b3", "a2b1", "a2b2", "a2b3"]

具有挑戰性的問題來了,如何對 N 個集合進行迪卡爾積運算呢,比如有這樣的集合資料:

var arrList = new List<string[]>
{
new string[] { "a1", "a2" },
new string[] { "b1", "b2", "b3" },
new string[] { "c1" },
// ...
};

如何對上面的 arrList 中的各個集合進行兩兩組合呢?在電商業務尤其是零售業務中的產品組合促銷中這種需求很常見,

下面是一個使用 SelectMany 的實作,需要用到遞回:

class Program
{
static void Main(string[] args)
{
var arrList = new List<string[]>
{
new string[] { "a1", "a2" },
new string[] { "b1", "b2", "b3" },
new string[] { "c1" },
// ...
};

var result = Recursion(arrList, 0, new List<string>());
result.ForEach(x => Console.WriteLine(x));
}

static List<string> Recursion(List<string[]> list, int start, List<string> result)
{
if (start >= list.Count)
return result;

if (result.Count == 0)
result = list[start].ToList();
else
result = result.SelectMany(x => list[start].Select(y => x + y)).ToList();

result = Recursion(list, start + 1, result);

return result;
}
}

輸出:

a1b1c1
a1b2c1
a1b3c1
a2b1c1
a2b2c1
a2b3c1

類似這種集合的迪卡爾積運算操作,也可以用 LINQ to Object 來代替 SelectMany 實作:

result = result.SelectMany(x => list[start].Select(y => x + y)).ToList();
// 等同使用擴展方法:
result = (from a in result from b in list[start] select a + b).ToList();

LINQ to Object 比擴展方法看上去易讀性更好,但寫起來擴展方法更方便,

Aggregate 聚合

Aggregate 擴展方法可以對一個集合依次執行類似累加器的操作,就像滾雪球一樣把資料逐步聚集在一起,比如實作從 1 加到 10,用 Aggregate 擴展方法就很方便:

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = numbers.Aggregate((prevSum, current) => prevSum + current);
// sum = 55

我們來決議一下它的執行步驟

  • 第一步,prevSum 取第一個元素的值,即 prevSum = 1
  • 第二步,把第一步得到的 prevSum 的值加上第二個元素,即 prevSum = prevSum + 2
  • 依此類推,第 i 步把第 i-1 得到的 prevSum 加上第 i 個元素

再來看一個字串的例子加深理解:

string[] stringList = { "Hello", "World", "!" };
string joinedString = stringList.Aggregate((prev, current) => prev + " " + current);
// joinedString = "Hello World !"

Aggregate 還有一個多載方法,可以指定累加器的初始值,我們來看一個比較綜合的復雜例子,假如我們有如下 1-12 的一個數字集合:

var items = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

現在我們想做如下計算:

  • 計算集合元素的總數個數
  • 計算值為偶數的元素個數
  • 收集每第 4 個元素

當然通過普通的回圈遍歷也可以實作這三個計算,但使用 Aggregate 會更簡潔,下面是 Aggregate 的實作:

var result = items.Aggregate(new { Total = 0, Even = 0, FourthItems = new List<int>() },
(accum, item) =>
new
{
Total = accum.Total + 1,
Even = accum.Even + (item % 2 == 0 ? 1 : 0),
FourthItems = (accum.Total + 1) % 4 == 0 ? new List<int>(accum.FourthItems) { item } : accum.FourthItems
}
);

// result:
// Total = 12
// Even = 6
// FourthItems = [4, 8, 12]

這里為了簡單起見使用匿名型別作為累加器的初始值,由于匿名型別的屬性是只讀的,所以在累加的程序都 new 了一個新物件,如果初始值使用的是自定義型別,那累加時就不需 new 新物件了,

Join 關聯查詢

和 SQL 查詢一樣,LINQ 同樣支持 Inner Join、Left Join、Right Join、Cross Join 和 Full Outer Join,有時候你可能看到不同的寫法,其實是同一個意思,比如 Left Outer Join 就是 Left Join,Join 是 Inner Join 省略了 Inner 等,

假設我們有下面兩個集合,分別表示左邊的資料和右邊的資料,

var first = new List<string>() { "a","b","c" }; // 左邊
var second = new List<string>() { "a", "c", "d" }; // 右邊

下面以此資料為例來演示各種關聯查詢,

Inner Join

var result = from f in first
join s in second on f equals s
select new { f, s };
// 等同使用擴展方法:
var result = first.Join(second,
f => f,
s => s,
(f, s) => new { f, s });

// result: {"a","a"}
// {"c","c"}

Left Join

var result = from f in first
join s in second on f equals s into temp
from t in temp.DefaultIfEmpty()
select new { First = f, Second = t };
// 或者:
var result = from f in first
from s in second.Where(x => x == f).DefaultIfEmpty()
select new { First = f, Second = s };

// 等同使用擴展方法:
var result = first.GroupJoin(second,
f => f,
s => s,
(f, s) => new { First = f, Second = s })
.SelectMany(temp => temp.Second.DefaultIfEmpty(),
(f, s) => new { First = f.First, Second = s });

// result: {"a","a"}
// {"b", null}
// {"c","c"}

Right Join

var result = from s in second
join f in first on s equals f into temp
from t in temp.DefaultIfEmpty()
select new { First = t, Second = s };
// 其它和 Left Join 類似

// result: {"a","a"}
// {"c","c"}
// {null,"d"}

Cross Join

var result = from f in first
from s in second
select new { f, s };

// result: {"a","a"}
// {"a","c"}
// {"a","d"}
// {"b","a"}
// {"b","c"}
// {"b","d"}
// {"c","a"}
// {"c","c"}
// {"c","d"}

Full Outer Join

var leftJoin = from f in first
join s in second on f equals s into temp
from t in temp.DefaultIfEmpty()
select new { First = f, Second = t };
var rightJoin = from s in second
join f in first on s equals f into temp
from t in temp.DefaultIfEmpty()
select new { First = t, Second = s };
var fullOuterJoin = leftJoin.Union(rightJoin);

根據多個鍵關聯

在 SQL 中,表與表進行關聯查詢時 on 條件可以指定多個鍵的邏輯判斷,用 and 或 or 連接,但 C# 的 LINQ 不支持 and 關鍵字,若要根據多鍵關聯,需要把要關聯的鍵值分別以相同的屬性名放到匿名物件中,然后使用 equals 比較兩個匿名物件是否相等,示例:

var stringProps = typeof(string).GetProperties();
var builderProps = typeof(StringBuilder).GetProperties();
var query =
from s in stringProps
join b in builderProps
on new { s.Name, s.PropertyType } equals new { b.Name, b.PropertyType }
select new
{
s.Name,
s.PropertyType
};

以上均使用兩個集合做為示例,LINQ 關聯查詢也支持多個集合關聯,就像 SQL 的多表關聯,只需往后繼續追加 join 操作即可,不再累述,

LINQ 關聯查與 SQL 相似,但使用上有很大區別,LINQ 關聯查詢的用法有很多,也很靈活,不用刻意去記住它們,只要熟悉簡單常用的,其它的在實際用到的時候再查詢相關檔案,

Skip & Take 分頁

Skip 擴展方法用來跳過從起始位置開始的指定數量的元素讀取集合;Take 擴展方法用來從集合中只讀取指定數量的元素,

var values = new[] { 5, 4, 3, 2, 1 };
var skipTwo = values.Skip(2); // { 3, 2, 1 }
var takeThree = values.Take(3); // { 5, 4, 3 }
var skipOneTakeTwo = values.Skip(1).Take(2); // { 4, 3 }

Skip 與 Take 兩個方法結合即可實作我們常見的分頁查詢:

public IEnumerable<T> GetPage<T>(this IEnumerable<T> collection, int pageNumber, int pageSize)
{
int startIndex = (pageNumber - 1) * pageSize;
return collection.Skip(startIndex).Take(pageSize);
}

使用過 EF (Core) 的同學一定很熟悉,

另外,還有 SkipWhile 和 TakeWhile 擴展方法,它與 Skip 和 Take 不同的是,它們的引數是具體的條件,SkipWhile 從起始位置開始忽略元素,直到匹配到符合條件的元素停止忽略,往后就是要查詢的結果;TakeWhile 從起始位置開始讀取符合條件的元素,一旦遇到不符合條件的就停止讀取,即使后面還有符合條件的也不再讀取,示例:

SkipWhile:

int[] list = { 42, 42, 6, 6, 6, 42 };
var result = list.SkipWhile(i => i == 42);
// result: 6, 6, 6, 42

TakeWhile:

int[] list = { 1, 10, 40, 50, 44, 70, 4 };
var result = list.TakeWhile(item => item < 50).ToList();
// result = { 1, 10, 40 }

Zip 拉鏈

Zip 擴展方法操作的物件是兩個集合,它就像拉鏈一樣,根據位置將兩個系列中的每個元素依次配對在一起,其接收的引數是一個 Func 實體,該 Func 實體允許我們成對在處理兩個集合中的元素,如果兩個集合中的元素個數不相等,那么多出來的將會被忽略,

示例:

int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = numbers.Zip(words, (n, w) => n + "=" + w);

foreach (string s in zip)
{
Console.WriteLine(s);
}

輸出:

3=three
5=five
7=seven

OfType 和 Cast 型別過濾與轉換

OfType 用于篩選集合中指定型別的元素,Cast 可以把集合轉換為指定型別,但要求源型別必須可以隱式轉換為目標型別,假如有如下資料:

interface IFoo { }
class Foo : IFoo { }
class Bar : IFoo { }

var item0 = new Foo();
var item1 = new Foo();
var item2 = new Bar();
var item3 = new Bar();
var collection = new IFoo[] { item0, item1, item2, item3 };

OfType 示例:

var foos = collection.OfType<Foo>(); // result: item0, item1
var bars = collection.OfType<Bar>(); // result: item2, item3
var foosAndBars = collection.OfType<IFoo>(); // result: item0, item1, item2, item3

// 等同于使用 Where
var foos = collection.Where(item => item is Foo); // result: item0, item1
var bars = collection.Where(item => item is Bar); // result: item2, item3

Cast 示例:

var bars = collection.Cast<Bar>();  // InvalidCastException 例外
var foos = collection.Cast<Foo>(); // InvalidCastException 例外
var foosAndBars = collection.Cast<IFoo>(); // OK

ToLookup 索引式查找

ToLookup 擴展方法回傳的是可索引查找的資料結構,它是一個 ILookup 實體,所有元素根據指定的鍵進行分組并可以按鍵進行索引,這樣說有點抽象,來看具體示例:

string[] array = { "one", "two", "three" };
// 根據元素字串長度創建一個查找物件
var lookup = array.ToLookup(item => item.Length);

// 查找字串長度為 3 的元素
var result = lookup[3];
// result: one,two

再來一個示例:

int[] array = { 1,2,3,4,5,6,7,8 };
// 創建一個奇偶查找(鍵為 0 和 1)
var lookup = array.ToLookup(item => item % 2);

// 查找偶數
var even = lookup[0];
// even: 2,4,6,8

// 查找奇數
var odd = lookup[1];
// odd: 1,3,5,7

Distinct 去重

Distinct 方法用來去除重復項,這個容易理解,示例:

int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };
var distinct = array.Distinct();
// distinct = { 1, 2, 3, 4, 5 }

簡單型別的集合呼叫 Distinct 方法使用的是默認的比較器,Distinct 方法用此比較器來判斷元素是否與其它元素重復,但對于自定義型別要實作去重則需要自定義比較器,示例:

public class IdEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y) => x.Id == y.Id;
public int GetHashCode(Person p) => p.Id;
}

public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}

class Program
{
static void Main(string[] args)
{
var people = new List<Person>();
var distinct = people.Distinct(new IdEqualityComparer());
}
}

ToDictionary 字典轉換

ToDictionary 擴展方法可以把集合 IEnumerable<TElement> 轉換為 Dictionary<TKey, TValue> 結構的字典,它接收一個 Func<TSource, TKey> 引數用來回傳每個元素指定的鍵與值,示例:

IEnumerable<User> users = GetUsers();
Dictionary<int, User> usersById = users.ToDictionary(x => x.Id);

如果不用 ToDictionary,你需要這樣寫:

IEnumerable<User> users = GetUsers();
Dictionary<int, User> usersById = new Dictionary<int, User>();
foreach (User u in users)
{
usersById.Add(u.Id, u);
}

上面 ToDictionary 回傳的字典資料中的值是整個元素,你也可以通過它的第二個引數來自定義字典的值,示例:

Dictionary<int, string> userNamesById = users.ToDictionary(x => x.Id, x => x.Name);

你也可以為轉換的字典指定其鍵是否區分大小寫,即自定義字典的 IComparer,示例:

Dictionary<string, User> usersByCaseInsenstiveName = users.ToDictionary(x =>x.Name,
StringComparer.InvariantCultureIgnoreCase);

var user1 =usersByCaseInsenstiveName["liam"];
var user2 =usersByCaseInsenstiveName["LIAM"];
user1 == user2; // true

注意,字典型別要求所有鍵不能重復,所以在使用 ToDictionary 方法時要確保作為字典的鍵的元素屬性不能有重復值,否則會拋出例外,

其它常見擴展方法

LINQ 還有很多其它常見的擴展方法,大家在平時應該用的比較多,比如 Where、Any、All 等,這里也選幾個簡單舉例介紹一下,

Range 和 Repeat

Range 和 Repeat 用于生成簡單的數字或字串系列,示例:

// 生成 1-100 的數字,即結果為 [1, 2, ..., 99, 100]
var range = Enumerable.Range(1, 100);

// 生成三個重復的字串“a”,即結果為 ["a", "a", "a"]
var repeatedValues = Enumerable.Repeat("a", 3);

Any 和 All

Any 用來判斷集合中是否存在任一一個元素符合條件,All 用來判斷集合中是否所有元素符合條件,示例:

var numbers = new int[] {1, 2, 3, 4, 5 };
bool result = numbers.Any(); // true
bool result = numbers.Any(x => x == 6); // false
bool result = numbers.All(x => x > 0); // true
bool result = numbers.All(x => x > 1); // false

Concat 和 Union

Concat 用來拼接兩個集合,不會去除重復元素,示例:

List<int> foo = newList<int> { 1, 2, 3 };
List<int> bar = newList<int> { 3, 4, 5 };
// 通過 Enumerable 類的靜態方法
var result = Enumerable.Concat(foo, bar).ToList(); // 1,2,3,3,4,5
// 通過擴展方法
var result = foo.Concat(bar).ToList(); // 1,2,3,3,4,5

Union 也是用來拼接兩個集合,與 Concat 不同的是,它會去除重復項,示例:

var result = foo.Union(bar); // 1,2,3,4,5

GroupBy 分組

GroupBy 擴展方法用來對集合進行分組,下面是一個根據奇偶進行分組的示例:

var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var grouped = list.GroupBy(x => x % 2 == 0);
// grouped: [1, 3, 5, 7, 9] 和 [2, 4, 6, 8]

還可以根據指定屬性進行分組:

public class Person
{
public int Age { get; set; }
public string Name { get; set; }
}

var people = new List<Person>();
var query = people
.GroupBy(x => x.Age)
.Select(g => { Age = g.Key, Count = g.Count() });

DefaultIfEmpty 空替換

在上面的關聯查詢中我們使用了 DefaultIfEmpty 擴展方法,它表示在沒有查詢到指定條件的元素時使用元素的默認值代替,其實 DefaultIfEmpty 還可以指定其它的默認值,示例:

var chars = new List<string>() { "a", "b", "c", "d" };
chars.Where(s => s.Length > 1).DefaultIfEmpty().First(); // 回傳 null
chars.DefaultIfEmpty("N/A").FirstOrDefault(); // 回傳 "a"
chars.Where(s => s.Length > 1).DefaultIfEmpty("N/A").FirstOrDefault(); // 回傳 "N/A"

SequenceEqual 集合相等

SequenceEqual 擴展方法用于比較集合系列各個相同位置的元素是否相等,示例:

int[] a = new int[] {1, 2, 3};
int[] b = new int[] {1, 2, 3};
int[] c = new int[] {1, 3, 2};

bool result1 = a.SequenceEqual(b); // true
bool result2 = a.SequenceEqual(c); // false

最后

還有一些常用和簡單的擴展方法就不舉例了,比如 OrderBy(排序)、Sum(求和)、Count(計數)、Reverse(反轉)等,同時歡迎大家補充本文遺漏的強大或好用的 LINQ 語法糖,


來源:精致碼農 ,作者liamwang

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/202391.html

標籤:C#

上一篇:ASP.NET Core MVC 專案中路由無法生效

下一篇:一路踩坑,被迫聊聊 C# 代碼除錯技巧和遠程除錯

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more