1. 程式人生 > >學習Linq之前必須要了解的擴展方法

學習Linq之前必須要了解的擴展方法

lis des ring return 圖片 hide 命名空間 改變 pac

本文主要以下面幾個方面來詳細講解擴展方法:在C#3.0之前沒有擴展方法的狀態(或者你不會使用不知道擴展方法的時候)、擴展方法的語法及怎麽使用、怎麽正確的使用擴展方法;

一、首先說一下在C#3.0之前沒有擴展方法的狀態(或者你不會使用不知道擴展方法的時候)

1、大家在項目中肯定遇到類似這樣的需求且項目很多地方都會用到:1.需要對一個對象進行可空判斷;2、對一個集合或者對象進行序列化;3、時間格式轉換;4、List與DataTabel之前轉換等等。

我想在沒有擴展方法之前大家基本上都是做一個類似common的靜態公共靜態類,寫一些靜態方法供項目各個調用調用 如:

技術分享圖片
 public static  class Common
    {
        /// <summary>
        /// 判斷是否為Null或者空
        /// </summary>
        /// <param name="obj">對象</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty( object obj)
        {
            if (obj == null
) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } }
View Code

其他類調用公共方法

技術分享圖片
 static void Main(string[] args)
        {
            string
str = "lxsh"; Common.IsNullOrEmpty(str); }
View Code

通過這樣也能完成上面所說的幾個需求,但是讓人感覺上端一直要顯示依賴Common這個靜態類,項目中就會大量充斥著這樣的代碼,看起來不那麽簡潔,而且也不利於後期的鏈式語法編程;

2、有時也會遇到這樣的情況:你想對某個類型加一些行為(方法),但你不能改變該類型的本身,因為是別人的代碼,遇到這樣情況你可能會增加一個繼承接口,或者一個抽象類,或者通過代理模式封裝一次,這樣顯然能達到目的但都很麻煩;

以上解決辦法都是在沒有使用擴展方法之前的解決方案,當你學會了擴展方法,你可能會有更好的選擇;

二、 接下來我們來說一下擴展方法的語法及使用

1、擴展方法必須具備以下幾個特征:

  • 必須是在非嵌套的、非泛型的靜態類中
  • 必須在靜態類中的靜態方法
  • 至少要有一個參數
  • 第一個參數的前綴必須加this關鍵字且不能有任何修飾符(如:ref,out)且參數類型不能為指針

例如:

技術分享圖片
 public static partial class Extensions
    {

        public static string ObjectToJSON(this object obj)
        {
            return JsonConvert.SerializeObject(obj, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
        }
        /// <summary>
        /// 判斷是否為Null或者空
        /// </summary>
        /// <param name="obj">對象</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this object obj)
        {
            if (obj == null)
                return true;
            else
            {
                string objStr = obj.ToString();
                return string.IsNullOrEmpty(objStr);
            }
        }

    }
View Code

2、怎麽使用擴展方法:

先引用擴展方法靜態類所在的命名空間,引用完成後,在調用的時候它在你對應類型實例上面有”智能感知“提示

技術分享圖片

3、擴展方法是怎麽被發現調用的

如果在using命令,將擴展方法引用到代碼中,擴展方法可以像類一下不加限制地在代碼中使用。如果編譯器認為一個表達試好像要使用一個實例方法,但沒有找到與這個方法調用兼容的實例方法,就會查找一個合適的擴展方法。它會檢查導入的所有命名空間和當前命名空間中所有的擴展方法,並匹配那些從表達式類型到擴展類型存在隱式轉換的擴展方法;

簡單一句話講:編譯器首先會查看這類型(包括父類)有沒有對應的該實例方法,如果有該實例方法他就不會執行擴展方法,如果沒有它就會找對應的擴展方法執行;

假如有一個 student類,它有一個實例方法say,再給他加一個擴展方法say

技術分享圖片
  public  class Student
    {
        public void Say()
        {
            Console.WriteLine("我是實例方法");
        }
    }


    public static class Extensions
    {
        public static void Say(this Student student)
        {
             Console.WriteLine("我是擴展方法");
        }

    }
View Code 技術分享圖片
  static void Main(string[] args)
        {
            Student student = new Student();
            student.Say();    
           
            Console.ReadKey();
        }
View Code

執行結果為:

技術分享圖片

還有一種情況,對子類和父類同時加了一個一樣的擴展方法,且都引用了他們名詞空間,優先調用子類的擴展方法(同樣適用於接口父子關系)

技術分享圖片
  public class Person
    {  
    }
    public  class Student:Person
    {
        public void Say()
        {
            Console.WriteLine("我是實例方法");
        }
    }   

    public static class Extensions
    {
        public static void Say(this Student student)
        {
             Console.WriteLine("我是擴展方法");
        }
        public static void GetName(this Student student)
        {
            Console.WriteLine("我是子類擴展方法");
        }
        public static void GetName(this Person student)
        {
            Console.WriteLine("我是父類擴展方法");
        }

    }
View Code 技術分享圖片
  static void Main(string[] args)
        {
            Student student = new Student();
            student.Say();
            student.GetName();
            Console.ReadKey();
        }
View Code

執行結果:
技術分享圖片

三、怎麽正確的使用擴展方法(建議)

接下來簡單講一下怎麽正確使用擴展方法:

1.如果在項目中使用擴展方法,首先需要要項目成員都熟悉擴展方法的使用

2.將擴展方法單獨放到一個單獨的命名空間裏,可有效的防止被誤用,建議擴展方法所屬擴展類盡量用partial類(如針對Object的擴展方法命名Extensions.Object、針對string的擴展方法命名Extensions.String),方便代碼維護

例如:Extensions.Object、Extensions.String

技術分享圖片
namespace Lucky.Proect.Core.Extensions
{
    public static partial class Extensions
    {

        public static string ObjectToJSON(this object obj)
        {
            return JsonConvert.SerializeObject(obj, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
        }
        /// <summary>
        /// 判斷是否為Null或者空
        /// </summary>
        /// <param name="obj">對象</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this object obj)
        {
            if (obj == null)
                return true;
            else
            {
                string objStr = obj.ToString();
                return string.IsNullOrEmpty(objStr);
            }
        }

    }
}
View Code

技術分享圖片
namespace Lucky.Proect.Core.Extensions
{
   public static partial   class Extensions
    {
          [DebuggerStepThrough] //該特性是用在方法前面的,在想要跳過的方法前面加上 
        public static T FromJson<T>(this string jsonStr)
        {
            return string.IsNullOrEmpty(jsonStr) ? default(T) : JsonConvert.DeserializeObject<T>(jsonStr);
        }
        /// <summary>
        /// 指示指定的字符串是 null、空或者僅由空白字符組成。
        /// </summary>
        [DebuggerStepThrough] //該特性是用在方法前面的,在想要跳過的方法前面加上 
        public static bool IsNullOrWhiteSpace(this string value)
        {
            return string.IsNullOrWhiteSpace(value);
        }
        /// <summary>
        /// 將Json字符串轉為DataTable
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static DataTable ToDataTable(this string jsonStr)
        {
            return jsonStr == null ? null : JsonConvert.DeserializeObject<DataTable>(jsonStr);
        }
    }
}
View Code

3.盡量不在在object上面寫太多的擴展方法,寫之前要多加思考,不然在項目使用中任何類型智能提示出現一推擴展方法,看起來比較雜亂,針對int的擴展方法應該寫在int類型上,針對datetime的擴展方法應該寫在datetime類型上不應該都寫在object類型上

4.如果方法名在擴展類型中已經使用,就不要再用這個名稱了,因為寫了也無效;

學習Linq之前必須要了解的擴展方法