擴展方法 之 基本數據篇

作者: CoolCode  來源: 博客園  發布時間: 2009-09-28 14:05  閱讀: 1723 次  推薦: 0   原文鏈接   [收藏]  

  前一篇我列舉了幾個最常用到的基于Asp.Net的擴展方法,而這一篇基于基本數據的擴展方法理應不會遜一籌,因為它不局限于Asp.Net。何謂基本數據,這里直接擺定義:

  C# 中有兩種基本數據類型:值類型和引用類型。 值類型包括:簡單類型、結構類型、枚舉類型;引用類型包括:Object 類型、類類型、接口、代表元、字符串類型、數組。

  說白了這篇就是擴展 int, string, double, DateTime...等基本類型。這么多數據類型,如果int來個擴展,double也來個擴展,肯定會是一個造金字塔工程。幸好有泛型幫我們,但是有時泛型也不是萬能的,這個以后有機會再說。

  為什么我們需要擴展方法?一句話:提高寫代碼的速度,語義也清晰。按道理說,基于基本數據的擴展方法應該經常被用到才有意義,否則只會“污染”被擴展的元素。而怎么才算常用,這可沒什么標準,也不是我一個人說了算。所以,以下的擴展方法大家就根據自己的經驗判斷是否常用吧,至少我的項目是用了不少。

1. In 判斷一個元素是否在一個集合里面

(這是我目前為止見到最好的擴展方法之一)

1.1 ScottGu 最初的版本:

step2  

1.2 后經 鶴沖天 的潤色:c#擴展方法奇思妙用高級篇一:改進 Scottgu 的 "In" 擴展

1.3 最后我也來湊個熱鬧:

   public static bool In(this T t, params T[] c)
        {
            return c.Contains(t);
            //return c.Any(i => i.Equals(t));
        }

示例:

bool exist1=  2.In(1, 2, 3);
string[] helloworld = { "Hello", "World", "!" };
bool exist2 = "Hello".In(helloworld );

2. InRange 判斷一個元素是否在某個范圍

public static bool InRange(this IComparable t, T minT, T maxT)
        {
            return t.CompareTo(minT) >= 0 && t.CompareTo(maxT) <= 0;
        }
        public static bool InRange(this IComparable t, object minT, object maxT)
        {
            return t.CompareTo(minT) >= 0 && t.CompareTo(maxT) <= 0;
        }

示例:

//判斷3是否在2~3的范圍
bool result1 = 3.InRange(2, 3);
 //判斷3.14是否在3.13~3.15的范圍
bool result2 = 3.14.InRange(3.13, 3.15);
//判斷今天是否在2000年1月1日~2010年1月1日的范圍
bool result3 = DateTime.Now.InRange(new DateTime(2000, 1, 1), new DateTime(2010, 1, 1));
//判斷牛B是否在牛A和牛C之間
bool result4 = "牛B".InRange("牛A", "牛C");

上面最后一個示例來源于這句網語:做一個徘徊于牛A和牛C之間的人

3. ForEach 遍歷集合

public static void ForEach(this IEnumerable source, Action action)
{
           foreach (T element in source)
           action(element);
}         
public static void ForEach(this IEnumerable source, Actionint> action)
{
            int i = 0;
            foreach (T element in source)
            action(element, i++);
 }

注:這兩個并非原創,但實在太通用,已經找不到出處。

示例1:Linq to SQL 批量更新

//Linq to SQL 
IQueryable query = ...;
query.ForEach(c => c.Name = "Bruce");
db.SubmitChanges();

示例2:設置行號

List list = ...;
list.ForEach((c,i) => c.Line = (i+1)); 

4. Clone 克隆一個對象

public static T Clone(this T t)
 {
       return (T)CloneObject(t);
}
        private static object CloneObject(object obj)
 {
            using (MemoryStream memStream = new MemoryStream())
        {
                BinaryFormatter binaryFormatter = new BinaryFormatter(null,   
                new StreamingContext(StreamingContextStates.Clone));
                binaryFormatter.Serialize(memStream, obj);
                memStream.Seek(0, SeekOrigin.Begin);
                return binaryFormatter.Deserialize(memStream);
        }
 }

示例1:克隆單個實體

Entity entity = new Entity { Name = "Bruce", Line = 1 };
            Entity cloneEntity = entity.Clone();
            bool same = entity.Equals(cloneEntity);
            // 被克隆的類必須標記為可序列化
             [Serializable]
            class Entity
           {
                  public string Name { get; set; }
                  public int Line { get; set; }
            }

最后entity.Equals(cloneEntity);的結果是false,表明已經成功克隆了一個新對象。

示例2:克隆集合

List list = new List();
            list.Add(new Entity { Name = "Bruce", Line = 1 });
            list.Add(new Entity { Name = "Jack", Line = 2 });
            list.Add(new Entity { Name = "Rose", Line = 3 });
            list.Add(new Entity { Name = "Tony", Line = 4 });
            List cloneList = list.Clone();

總結:

擴展方法為我們封裝了常用的邏輯,與以往靜態方法不同的是,從使用者的角度來看已經不用關心這個方法是來自于那個類,主要記著命名空間就可以。所以,一般做法是,所有擴展方法屬于同一命名空間,并按被擴展的類型分類,如下圖:

image

最后要說的是,其實string類型的擴展方法應該是使用頻率最高的,但基于string的擴展方法網上隨便一抓一大把,這里就不重復列舉了。

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()