[C#.NET] 擴充方法 - 為 IEnumerable<T> 擴充查詢欄位方法

[C#.NET] 擴充方法 - 為 IEnumerable<T> 擴充查詢欄位方法

集合有個 Contains 方法可判斷集合內有沒有該物件,用法如下


if (intList.Contains(5))
    Console.WriteLine("Exist");
else
    Console.WriteLine("No Exist");

但集合內存放的是一個類別時,原本的 Contains 就不敷使用。

假設我有個類別


{
    public string Name { get; set; }
    public int Age { get; set; }
}
在集合裡面裝了這些東西

list.Add(new Customer() { Name = "jordan", Age = 19 });
list.Add(new Customer() { Name = "小章", Age = 20 });
list.Add(new Customer() { Name = "盧克", Age = 34 });
list.Add(new Customer() { Name = "9gy", Age = 29 });
list.Add(new Customer() { Name = "小盧克", Age = 17 });
假設我要查詢某個欄位是否存在,以往我都會這麼寫

            where data.Name == "小章"
            select data;

int count = query.Count();
if (count > 0)
{
    Console.WriteLine("Exist");
}
else
{
    Console.WriteLine("No Exist");
}
lambda寫法

if (count > 0)
{
    Console.WriteLine("Exist");
}
else
{
    Console.WriteLine("No Exist");
}
用迴圈也可以

{
    if (item.Name=="小章")
    {
         Console.WriteLine("Exist");
         return;
    }
}
Console.WriteLine("No Exist");
這樣的東西不斷的出現在專案裡也挺累人的,不如就為它寫個擴充方法,相關寫法請參考[C#.NET] C# 3.0 (VS 2008) 語言新特性,下列方法主要是利用反射進行欄位查詢,
1.IsContains:回傳查詢欄位是否存在
2.Contains:回傳查詢欄位的值
3.IndexOf:回傳查詢欄位的索引值

using System.Linq;
using System.Reflection;

namespace System.Servconn.Extensions
{
    public static partial class ExtendSyntax
    {
        public static bool IsContains<T>(this IEnumerable<T> List, string PropertyName, object Value)
        {
            object Exist = null; bool IsExist = false; int Position = -1;
            contains<T>(List, PropertyName, Value, ref Exist, ref IsExist, ref Position);
            return IsExist;
        }

        public static T Contains<T>(this IEnumerable<T> list, string PropertyName, object Value)
        {
            object Exist = null; bool IsExist = false; int Position = -1;
            contains<T>(list, PropertyName, Value, ref Exist, ref IsExist, ref Position);

            if (Exist != null)
            {
                return (T)Exist;
            }
            else
            {
                return default(T);
            }
        }

        public static int IndexOf<T>(this IEnumerable<T> List, string PropertyName, object Value)
        {
            object Exist = null; bool IsExist = false; int Position = -1;
            contains<T>(List, PropertyName, Value, ref Exist, ref IsExist, ref Position);

            return Position;
        }

        private static void contains<T>(this IEnumerable<T> List, string PropertyName, object Value, ref object Exist, ref bool IsExist, ref int Position)
        {
            if (List == null)
            {
                throw new ArgumentNullException("List");
            }
            if (string.IsNullOrEmpty(PropertyName))
            {
                throw new ArgumentNullException("PropertyName");
            }
            if (Value == null)
            {
                throw new ArgumentNullException("Value");
            }

            Type type = typeof(T);
            PropertyInfo propertyInfo = type.GetProperty(PropertyName);
            if (propertyInfo == null)
            {
                throw new NotSupportedException(PropertyName);
            }

            var query = from data in List
                        where propertyInfo.GetValue(data, null).Equals(Value)
                        let Index = List.IndexOf(data)
                        select new { Index, data };
            if (query.Count() > 0)
            {
                IsExist = true;
                Exist = query.First().data;
                Position = query.First().Index;
            }
        }
    }
}
如此一來便可為List<T>增加上述屬性,正確來說凡是有繼承IEnumerable<T>的類別,都可以享用上面的方法。
image

image

image


補充:

經91哥提醒,

Any 方法 可以判斷欄位是否存在

ElementAt<TSource>可以依索引值取得相關的值

白寫了(攤手)

查詢索引值的部份用了牛刀殺雞浪費了效能(反射),91哥也建議使用delegate做掉,於是我改成


{
    if (List == null)
    {
        throw new ArgumentNullException("list");
    }
    if (Condition == null)
    {
        throw new ArgumentNullException("predicate");
    }

    int index = 0;
    foreach (var item in List)
    {
        if (Condition(item))
        {
            return index;
        }
        index++;
    }
    return -1;
}

image

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo