iT邦幫忙

0

C# Linq

今天 來講講Linq這個好用的東西吧

不過我不會著墨在他哪些方法怎麼用(這個自己Google應該就可以了

而是從另外一個面向來聊聊

先上Code 今天就拿可憐的學生作為白老鼠吧

public enum Gender
{
    Male,
    Female,
}

public class Student
{
    public string LastName { get; set; }

    public string FirstName { get; set; }

    public int Age { get; set; }

    public Gender Gender { get; set; }
}

接下來下個簡單的查詢

我想查年齡16歲且是女性的學生

static void Main(string[] args)
{
    var students = new List<Student>();
    var result = students
        .Where(student => student.Age == 16 && student.Gender == Gender.Female)
        .ToList();
}

非常好~這麼簡單難不倒我~

但是通常真正實作上才不會讓你寫hardcode

所以會有個input 讓你依照input去查詢

我就寫個class當作input進來的結果

public class QueryInput
{
    /// <summary>
    /// 如果是空字串就不列入查詢條件
    /// </summary>
    public string LastName { get; set; }
    /// <summary>
    /// 如果是空字串就不列入查詢條件
    /// </summary>
    public string FirstName { get; set; }
    /// <summary>
    /// 如果是空就不列入查詢條件
    /// </summary>
    public int? Age { get; set; }
    /// <summary>
    /// 如果是空就不列入查詢條件
    /// </summary>
    public Gender? Gender { get; set; }
}

這種還算簡單 會有更複雜的 例如 可能要年齡大於某個值是落在某個區間

不過這個就不是這次的重點 就不特別提了

好 現在的需求是 要依照input的參數來查詢

所以我常常可以看到這種程式碼


static void Main(string[] args)
{
    var students = new List<Student>();
    var queryInput = new QueryInput();
    var result = students;
    if (string.IsNullOrWhiteSpace(queryInput.FirstName))
    {
        result = result.Where(student => student.FirstName == queryInput.FirstName).ToList();
    }
    if (string.IsNullOrWhiteSpace(queryInput.LastName))
    {
        result = result.Where(student => student.LastName == queryInput.LastName).ToList();
    }
    if (queryInput.Age.HasValue)
    {
        result = result.Where(student => student.Age == queryInput.Age).ToList();
    }
    if (queryInput.Gender.HasValue)
    {
        result = result.Where(student => student.Gender == queryInput.Gender).ToList();
    }
}

嘛..就結果來說答案是對了

但Linq有個非常重要的特性就是 延遲查詢(Deferred Execution

這是什麼意思呢? 就是你設定查詢語句時 並不會真的去執行

只有在"需要的時候"才會去完整執行你的查詢語句

例如 ToList,ToArray Foreach, First, Count...等

所以照上面的寫法 如果每個查詢條件都有去下 總共會跑 4次迴圈

static void Main(string[] args)
{
    var students = new List<Student>();
    var queryInput = new QueryInput();
    var query = students.AsEnumerable();

    if (string.IsNullOrWhiteSpace(queryInput.FirstName))
    {
        query = query.Where(student => student.FirstName == queryInput.FirstName);
    }
    if (string.IsNullOrWhiteSpace(queryInput.LastName))
    {
        query = query.Where(student => student.LastName == queryInput.LastName);
    }
    if (queryInput.Age.HasValue)
    {
        query = query.Where(student => student.Age == queryInput.Age);
    }
    if (queryInput.Gender.HasValue)
    {
        query = query.Where(student => student.Gender == queryInput.Gender);
    }
    var result = query.ToList();
}

像這樣 中間段其實就只是在設定查詢語句而已 真正查詢會在最後一行才執行

也只會跑一次迴圈而已

另外因為延遲查詢的特性 如果想知道Count

var result = query.ToList();
var count = query.Count();//不要這樣寫!
var count = result.Count();

因為如果再ToList一次 他會再次查詢

我們可以寫個範例來看看

static void Main(string[] args)
{
    var datas = new List<int>()
    { 1,2,3,4,5};
    var query = datas.Where(x => x % 2 == 0);

    datas.Clear();
    datas.Add(8);

    var result = query.ToList();//8
    datas.Clear();
    var count = query.Count();//0

}

現在應該對延遲查詢有些概念了吧?

所以不要任意去使用ToList 先設定好查詢方式 只有在需要的時候才去作查詢!


尚未有邦友留言

立即登入留言