在net中json序列化與反序列化 面向對象六大原則 (第一篇) 一步一步帶你瞭解linq to Object 10分鐘淺談泛型協變與逆變

在net中json序列化與反序列化

 
準備好飲料,咱們一塊兒來玩玩JSON,什麼是Json:一種數據表示形式,JSON:JavaScript Object Notation對象表示法

Json語法規則:javascript

  • 數據在鍵值對中
  • 數據由逗號分隔
  • 花括號保存對象
  • 方括號保存數組

1、JSON的表現形式

在javascript中對象的表現形式以下  php

  1.對象表現形式:  html

    <script type="text/javascript">
var jsonObject={code:0,resultmsg:'成功'};
alert(jsonObject.code);
    </script>

  2.數組表現形式: java

 

複製代碼
    <script type="text/javascript">
 var personInfo=[
     {name:'張三',Age:18,sex:'男'},
     {name:'小倩',Age:19,sex:'女'},
     {name:'小明',Age:18,sex:'男'}
 ];
 alert(personInfo[0].name);
    </script>
複製代碼

  3.對象數組聯合表現形式: 面試

複製代碼
<script type="text/javascript">
 var Studennt=[
     {name:'張三',Age:18,sex:'男',succes:[
         {name:'語文',succ:89.5},
         {name:'數學',succ:89.5},
         {name:'外語',succ:89.5}
     ]
    },
     {name:'小倩',Age:19,sex:'女',succes:[
         {name:'語文',succ:89.5},
         {name:'數學',succ:89.5},
         {name:'外語',succ:89.5}
     ]},
     {name:'小明',Age:18,sex:'男',succes:[
         {name:'語文',succ:89.5},
         {name:'數學',succ:89.5},
         {name:'外語',succ:89.5}
     ]}
 ];
 alert(Studennt[0].name);
    </script>
複製代碼

 

2、什麼是JSON序列化與反序列化?

序列化是將對象狀態轉換爲可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換爲對象。這兩個過程結合起來,能夠輕鬆地存儲和傳輸數據。
簡單來講就是對象轉換成爲JSON格式字符串咱們稱爲序列化,反之JSON字符串轉換爲對象咱們稱爲反序列化。
下邊咱們準備點基礎類,部門信息類
複製代碼
using System;

namespace MySerialize.Entity
{
    public class DeptInfo
    {
        public int Id { get; set; }
        public string DeptName { get; set; }

        public DateTime CreateTime { get; set; }

    }
}
複製代碼

 

枚舉類,分別是職務類別,人員狀態。這裏簡單說下枚舉的特色是若是枚舉值不指定起始位置默認從0開始,若是指定枚舉第一個值則從指定的第一位開始一次遞增長一計算枚舉值,若是每一個枚舉值都賦值則按賦值計算,
不理解這句話不要緊不影響學習JSON正反序列化。
複製代碼
using System;
namespace MySerialize.Entity
{
    /// <summary>
    /// 職務類別
    /// </summary>
   public enum JobType
    {
        董事長,
        總經理,
        總監,
        部門經理,
        人事專員,
        職員,
        工程師,
        其餘
    }

    public enum PersonType
    {
        在職,離職,退休,停職
    }
}
複製代碼

 

用戶信息類
複製代碼
using System;
using System.Collections.Generic;

namespace MySerialize.Entity
{
   public class UserInfo
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        /// <summary>
        /// 姓
        /// </summary>
        public string FirstName { get; set; }
        /// <summary>
        /// 名
        /// </summary>
        public string LastName { get; set; }
        public string PassWord { get; set; }

        public string Phone { get; set; }

        public string Address { get; set; }

        public DeptInfo Dept { get; set; }

        public JobType DeptType { get; set; }

        public PersonType UserType { get; set; }
        /// <summary>
        /// 職業技能
        /// </summary>
        public Dictionary<int, string> UserSkill { get; set; }
        /// <summary>
        /// 特長
        /// </summary>
        public Dictionary<string, string> UserStrong { get; set; }
    }
}
複製代碼
數據初始化類
複製代碼
using MySerialize.Entity;
using System;
using System.Collections.Generic;
 
namespace MySerialize
{
   public class DataFactory
    {
        /// <summary>
        /// 獲取全部專業技能
        /// </summary>
        /// <returns></returns>
        public static Dictionary<int, string> GetSkillAll() {
            Dictionary<int, string> DictionarySkill = new Dictionary<int, string>();
            DictionarySkill.Add(1, "1234");
            DictionarySkill.Add(2, "abcd");
            DictionarySkill.Add(3, "大中國");
            DictionarySkill.Add(4, "學習");
            DictionarySkill.Add(5, "上網");
            return DictionarySkill;
        }
        /// <summary>
        /// 獲取全部的特長
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, string> GetStrongAll()
        {
            Dictionary<string, string> DictionaryStrong = new Dictionary<string, string>();
            DictionaryStrong.Add("1", "abcdefg");
            DictionaryStrong.Add("2", "abcdefg123");
            DictionaryStrong.Add("3", "tvbcd");
            DictionaryStrong.Add("4", "您吃了嗎");
            DictionaryStrong.Add("5", "吃了嗎您呢");
            DictionaryStrong.Add("6", "tvbc 早上好");
            DictionaryStrong.Add("7", "vbbc  晚上好");
            return DictionaryStrong;
        }
        public static List<UserInfo> BuildUserList()
        {
            DeptInfo dept0 = new DeptInfo() { CreateTime = DateTime.Now, DeptName = "開發部", Id = 1 };
            DeptInfo dept1 = new DeptInfo() { CreateTime = DateTime.Now, DeptName = "電商事業部", Id = 2 };
            DeptInfo dept2 = new DeptInfo() { CreateTime = DateTime.Now, DeptName = "成功部", Id = 3 };
            DeptInfo dept3 = new DeptInfo() { CreateTime = DateTime.Now, DeptName = "人力資源管理部", Id = 4 };
            List<UserInfo> list = new List<UserInfo>();
            list.Add(new UserInfo()
            {
                Address = "北京昌平",
                DeptType = JobType.工程師,
                Dept = dept0,
                Id = 1,
                FirstName = "張",
                LastName = "三",
                PassWord = "",
                Phone = "13122222222222",
                UserName = "wbc",
                UserType = PersonType.在職,
                UserSkill = GetSkillAll(),
                UserStrong = GetStrongAll()
            });
            list.Add(new UserInfo()
            {
                Address = "北京昌平",
                DeptType = JobType.工程師,
                Dept = dept0,
                Id = 5,
                FirstName = "張",
                LastName = "三",
                PassWord = "",
                Phone = "13122222222222",
                UserName = "wbc",
                UserType = PersonType.在職,
                UserSkill = GetSkillAll(),
                UserStrong = GetStrongAll()
            });
            list.Add(new UserInfo()
            {
                Address = "北京昌平",
                DeptType = JobType.工程師,
                Dept = dept3,
                Id = 3,
                FirstName = "張",
                LastName = "三",
                PassWord = "",
                Phone = "13122222222222",
                UserName = "wbc",
                UserType = PersonType.在職,
                UserSkill = GetSkillAll(),
                UserStrong = GetStrongAll()
            });
            list.Add(new UserInfo()
            {
                Address = "北京昌平",
                DeptType = JobType.工程師,
                Dept = dept2,
                Id = 2,
                FirstName = "wwdd",
                LastName = "三",
                PassWord = "",
                Phone = "13122222222222",
                UserName = "wbc",
                UserType = PersonType.在職,
                UserSkill = GetSkillAll(),
                UserStrong = GetStrongAll()
            });
            list.Add(new UserInfo()
            {
                Address = "北京昌平",
                DeptType = JobType.工程師,
                Dept = dept1,
                Id = 4,
                FirstName = "wang",
                LastName = "三",
                PassWord = "",
                Phone = "13122222222222",
                UserName = "wbc",
                UserType = PersonType.在職,
                UserSkill = GetSkillAll(),
                UserStrong = GetStrongAll()
            });
            return list;

        }
    }
}
複製代碼

3、常見Json序列化和反序列化類

  1.DataContractJsonSerializer 類序列化和反序列化:sql

DataContractJsonSerializer 類在 System.Runtime.Serialization.Json這個命名空間下,在net 4.0裏面,而這個命名空間在  System.Runtime.Serialization.dll中typescript

複製代碼
 List<UserInfo> list=  DataFactory.BuildUserList();//獲取基礎數據
            //對象的系列化
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<UserInfo>));
            MemoryStream ms = new MemoryStream();
            ser.WriteObject(ms, list);
            string jsonString = Encoding.UTF8.GetString(ms.ToArray());
            ms.Close();
            //反序列化
             ser = new DataContractJsonSerializer(typeof(List<UserInfo>));
             ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
            List<UserInfo> obj = (List<UserInfo>)ser.ReadObject(ms);
複製代碼

  2.JavaScriptSerializer 類序列化和反序列化:編程

 JavaScriptSerializer 類在 System.Web.Script.Serialization命名空間下了,在net3.0裏面,而這個命名空間在  System.Web.Extensions.dll 中json

 

複製代碼
 Dictionary<string, string> dictionaryStrong=  new Dictionary<string, string>();
            dictionaryStrong.Add("1","22222222222222");
            UserInfo user = new UserInfo() {
                Id=1,
                Dept =new DeptInfo() { CreateTime=DateTime.Now,Id=1,DeptName="開發部"},
                Address="北京北京市",
                DeptType=JobType.工程師,
                FirstName="王",
                LastName="柏成",
                PassWord="",
                Phone="13126994771",
                UserName="wbc",
                UserSkill=null,
                UserStrong= dictionaryStrong,
                UserType=PersonType.在職
            };
            //序列化
            System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();
           string jsonString = jss.Serialize(user);
            txtData.Text = jsonString;
            //反序列化
            UserInfo obj = jss.Deserialize<UserInfo>(jsonString);
複製代碼

  3.JsonConvert類序列化和反序列化:小程序

 JsonConvert類在 Newtonsoft.Json 命名空間下了,而這個命名空間在Newtonsoft.Json.dll 中,而這個dll 只是第三方的一箇中間件,咱們能夠經過nuget 獲取並引用。

  List<UserInfo> list = DataFactory.BuildUserList();//獲取基礎數據
            //對象的系列化
            string jsonString= JsonConvert.SerializeObject(list);
            txtData.Text = jsonString;
            //反序列化
            List<UserInfo> obj = JsonConvert.DeserializeObject<List<UserInfo>>(jsonString);

 

   4. 簡單學習 linq to Json:

  linq to Json 是在Newtonsoft.Json.dll 的 Newtonsoft.Json.linq 命名空間下. json 操做類以下

className(類名) describe(說明)
 
JObject
 
用於操做JSON對象
 
JArray
用語操做JSON數組
 
 
JValue
 
表示數組中的值
 
JProperty
表示對象中的屬性,以"key/value"形式
 
JToken
用於存放Linq to JSON查詢後的結果

 

 建立Json對象和數組組合:

複製代碼
   JArray jArray = new JArray();
                JObject staff = new JObject();
                staff.Add(new JProperty("Name", "wangbaicheng"));
                staff.Add(new JProperty("Age", 33));
                staff.Add(new JProperty("Department", "銷售部"));
                staff.Add(new JProperty("Leader", new JObject(new JProperty("Name", "feifei"), new JProperty("Age", 30), new JProperty("Department", "chanpin"))));
                jArray.Add(staff);
                jArray.Add(staff);
                jArray.Add(staff);
                staff.Add(new JProperty("Array", jArray));
                jArray = new JArray();
                jArray.Add(new JValue("1"));
                jArray.Add(new JValue("2"));
                jArray.Add(new JValue("3"));
                jArray.Add(new JValue("4"));
                staff.Add(new JProperty("arr", jArray));
                txtData.Text = staff.ToString();
複製代碼

 

咱們還能夠經過如字符串獲取Json 對象,具體不演示了,看以下表格

方法   說明
JObject.Parse(string json)
json含有JSON對象的字符串,返回爲JObject對象,最外層是對象
JObject.FromObject(object o)

o爲要轉化的對象,返回一個JObject對象

JObject.Load(JsonReader reader)
reader包含着JSON對象的內容,返回一個JObject對象
JArray.Parse(string json)
 json含有JSON數組的字符串,返回爲JArray對象,最外層是數組
 
JArray.FromObject(object o)
 o爲要轉化的對象,返回一個JArray對象
 
JArray.Load(JsonReader reader)
 reader包含着JSON對象的內容,返回一個JArray對象

 

 

 

 

 

 

 

 

 

 

現有以下Json

{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"},\"Array\":[{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"}},{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"}},{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"}}],\"arr\":[\"1\",\"2\",\"3\",\"4\"]}

咱們來看下使用linq 和使用對象來解析Json 

複製代碼
 //對象解析json和linq 解析json 
            {
                string json = "{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"},\"Array\":[{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"}},{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"}},{\"Name\":\"wangbaicheng\",\"Age\":33,\"Department\":\"銷售部\",\"Leader\":{\"Name\":\"feifei\",\"Age\":30,\"Department\":\"chanpin\"}}],\"arr\":[\"1\",\"2\",\"3\",\"4\"]}";
                JObject jObject = JObject.Parse(json);

                //使用對象解析
              string name=  jObject["Name"].ToString();//注意大小寫
                name = jObject.Value<string>("Name");//注意大小寫
                JArray array= jObject.Value<JArray>("Array");
                for (int i = 0; i < array.Count; i++)
                {
                    JToken token=   array[i];
                    JObject obj = token as JObject;
                    Console.WriteLine("對象解析"+obj.Value<string>("Name"));
                }
                //linq 解析  
                var names = from staff in jObject["Array"].Children()
                            select (string)staff["Name"];
                foreach (var n in names)
                    Console.WriteLine("linq解析"+n);
            }
複製代碼

 

這裏就不過多的深刻了,畢竟咱們大多數的時候仍是比較喜歡json 轉換成爲咱們本身定義的對象的。

4、封裝本身的JsonHelper 類

 

複製代碼
  public static class JsonHelper
    {
        #region System.Runtime.Serialization net 4.0
        /// <summary>
        /// 對象序列化爲JSON
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="_t"></param>
        /// <returns></returns>
        public static string ObjectToJson<T>(this T _t)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            MemoryStream ms = new MemoryStream();
            ser.WriteObject(ms, _t);

            string jsonString = Encoding.UTF8.GetString(ms.ToArray());
            ms.Close();
            return jsonString;
        }
        /// <summary>
        /// 對象反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        public static T JsonToObject<T>(this string jsonString)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
            T obj = (T)ser.ReadObject(ms);
            return obj;
        }
        #endregion
        #region net3.0 System.Web.Extensions.dll
        /// <summary>
        /// 使用net 3.0 json 反序列化,支持json字符串屬性不帶引號
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        public static T JsonToObj<T>(this string jsonString)
        {
            //引用 System.Web.Extensions.dll
            System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();
            return jss.Deserialize<T>(jsonString);
        }
        /// <summary>
        /// 使用net 3.5 對象序列化成爲json 反序列化,支持json字符串屬性不帶引號
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        public static string ObjToJson<T>(this T t)
        {
            //引用 System.Web.Extensions.dll
            System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer();
            return jss.Serialize(t);
        }
        #endregion 

        /// <summary>
        /// JsonConvert.SerializeObject
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJson<T>(this T obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// JsonConvert.DeserializeObject
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="content"></param>
        /// <returns></returns>
        public static T ToObject<T>(this string content)
        {
            return JsonConvert.DeserializeObject<T>(content);
        }
    }
複製代碼

 

 

 

5、Json 深刻

 咱們都知道,在js中json的key 是可使用數字的,咱們學習了三種序列化方式,如何把一個json 的key 爲數字轉換成爲對象,咱們不少開發人員可能都會遇到過。

js 代碼以下

複製代碼
<script type="text/javascript">
var obj={1:123,2:456};
alert("obj[1]="+obj[1]);
var objText={"1":123,"2":456};
alert("objText[1]="+objText[1]);
alert("objText[1]="+objText["2"]);
 </script>
複製代碼

 

在微軟,很早以前就想到了這一解決方案,可是在4.0升級的時候,升級出來一個bug ,DataContractJsonSerializer 再也不支持key 爲數字轉換,可是其餘的兩種方式都支持

咱們先來看下 JavaScriptSerializer 是如何序列化和反序列化key 爲數字的json 。

 1.JavaScriptSerializer 類序列化和反序列化 key 爲數字:

 

複製代碼
 Dictionary<int, string> dictionary1 = DataFactory.GetSkillAll();
                Dictionary<string, string> dictionary2 = DataFactory.GetStrongAll();
                try
                {
                    string json = dictionary1.ObjToJson();
                    Dictionary<int, string> d = json.JsonToObj<Dictionary<int, string>>();
                }
                catch
                {


                }
                try
                {
                    string json = dictionary2.ObjToJson();
                    Dictionary<string, string> d = json.JsonToObj<Dictionary<string, string>>();
                }
                catch
                {


                }
複製代碼

 

 

 

咱們上述代碼分別爲兩個字典,字典值均爲數字,只是一個是字符串類型的,一個是整數類型的,整數類型的沒法序列化和反序列化,字符串類型的能夠序列化和反序列化。

看看序列化結果。

{"1":"abcdefg","2":"abcdefg123","3":"tvbcd","4":"您吃了嗎","5":"吃了嗎您呢","6":"tvbc 早上好","7":"vbbc  晚上好"}

也就是說,微軟在早期是隻支持字符串類型的數字key

 

  2.JsonConvert類序列化和反序列化:

 

 這個放心,不論key 是int 類型仍是string 類型,都支持的,咱們看下案列

 

Dictionary<int, string> dictionary1 = DataFactory.GetSkillAll();
            Dictionary<string, string> dictionary2 = DataFactory.GetStrongAll();
  string json1= dictionary1.ToJson();
                string json2=dictionary2.ToJson();
                Console.WriteLine(json1);
                Console.WriteLine(json2);

 

 

源碼下載地址: 點擊下載

 

姓名:王柏成 英文名:WbcSky QQ:1477865775 電子郵件:w329357255@126.com
 
 
 

面向對象六大原則

 

 

這是設計模式系列開篇的第一篇文章。也是我學習設計模式過程當中的總結。這篇文章主要講的是面向對象設計中,咱們應該遵循的六大原則。只有掌握了這些原則,咱們才能更好的理解設計模式。
咱們接下來要介紹如下6個內容。

  1. 單一職責原則——SRP
  2. 開閉原則——OCP
  3. 裏式替換原則——LSP
  4. 依賴倒置原則——DIP
  5. 接口隔離原則——ISP
  6. 迪米特原則——LOD

單一職責原則

單一職責原則的定義是就一個類而言,應該僅有一個引發他變化的緣由。也就是說一個類應該只負責一件事情。若是一個類負責了方法M1,方法M2兩個不一樣的事情,當M1方法發生變化的時候,咱們須要修改這個類的M1方法,可是這個時候就有可能致使M2方法不能工做。這個不是咱們期待的,可是因爲這種設計卻頗有可能發生。因此這個時候,咱們須要把M1方法,M2方法單獨分離成兩個類。讓每一個類只專心處理本身的方法。
單一職責原則的好處以下:

  1. 能夠下降類的複雜度,一個類只負責一項職責,這樣邏輯也簡單不少
  2. 提升類的可讀性,和系統的維護性,由於不會有其餘奇怪的方法來干擾咱們理解這個類的含義
  3. 當發生變化的時候,能將變化的影響降到最小,由於只會在這個類中作出修改。

開閉原則

開閉原則和單一職責原則同樣,是很是基礎並且通常是常識的原則。開閉原則的定義是軟件中的對象(類,模塊,函數等)應該對於擴展是開放的,可是對於修改是關閉的。
當需求發生改變的時候,咱們須要對代碼進行修改,這個時候咱們應該儘可能去擴展原來的代碼,而不是去修改原來的代碼,由於這樣可能會引發更多的問題。
這個準則和單一職責原則同樣,是一個你們都這樣去認爲可是又沒規定具體該如何去作的一種原則。
開閉原則咱們能夠用一種方式來確保他,咱們用抽象去構建框架,用實現擴展細節。這樣當發生修改的時候,咱們就直接用抽象了派生一個具體類去實現修改。

里氏替換原則

里氏替換原則是一個很是有用的一個概念。他的定義

若是對每個類型爲T1的對象o1,都有類型爲T2的對象o2,使得以T1定義的全部程序P在全部對象o1都替換成o2的時候,程序P的行爲都沒有發生變化,那麼類型T2是類型T1的子類型。

這樣說有點複雜,其實有一個簡單的定義

全部引用基類的地方必須可以透明地使用其子類的對象。

里氏替換原則通俗的去講就是:子類能夠去擴展父類的功能,可是不能改變父類原有的功能。他包含如下幾層意思:

  1. 子類能夠實現父類的抽象方法,可是不能覆蓋父類的非抽象方法。
  2. 子類能夠增長本身獨有的方法。
  3. 當子類的方法重載父類的方法時候,方法的形參要比父類的方法的輸入參數更加寬鬆。
  4. 當子類的方法實現父類的抽象方法時,方法的返回值要比父類更嚴格。

里氏替換原則之因此這樣要求是由於繼承有不少缺點,他雖然是複用代碼的一種方法,但同時繼承在必定程度上違反了封裝。父類的屬性和方法對子類都是透明的,子類能夠隨意修改父類的成員。這也致使了,若是需求變動,子類對父類的方法進行一些複寫的時候,其餘的子類沒法正常工做。因此里氏替換法則被提出來。
確保程序遵循里氏替換原則能夠要求咱們的程序創建抽象,經過抽象去創建規範,而後用實現去擴展細節,這個是否是很耳熟,對,里氏替換原則和開閉原則每每是相互依存的。

依賴倒置原則

依賴倒置原則指的是一種特殊的解耦方式,使得高層次的模塊不該該依賴於低層次的模塊的實現細節的目的,依賴模塊被顛倒了。
這也是一個讓人難懂的定義,他能夠簡單來講就是

高層模塊不該該依賴底層模塊,二者都應該依賴其抽象
抽象不該該依賴細節
細節應該依賴抽象

在Java 中抽象指的是接口或者抽象類,二者皆不能實例化。而細節就是實現類,也就是實現了接口或者繼承了抽象類的類。他是能夠被實例化的。高層模塊指的是調用端,底層模塊是具體的實現類。在Java中,依賴倒置原則是指模塊間的依賴是經過抽象來發生的,實現類之間不發生直接的依賴關係,其依賴關係是經過接口是來實現的。這就是俗稱的面向接口編程。
咱們下面有一個例子來說述這個問題。這個例子是工人用錘子來修理東西。咱們的代碼以下:

public class Hammer { public String function(){ return "用錘子修理東西"; } } public class Worker { public void fix(Hammer hammer){ System.out.println("工人" + hammer.function()); } public static void main(String[] args) { new Worker().fix(new Hammer()); } }

這個是一個很簡單的例子,可是若是咱們要新增長一個功能,工人用 螺絲刀來修理東西,在這個類,咱們發現是很難作的。由於咱們Worker類依賴於一個具體的實現類Hammer。因此咱們用到面向接口編程的思想,改爲以下的代碼:

public interface Tools { public String function(); }

而後咱們的Worker是經過這個接口來於其餘細節類進行依賴。代碼以下:

public class Worker { public void fix(Tools tool){ System.out.println("工人" + tool.function()); } public static void main(String[] args) { new Worker().fix(new Hammer()); new Worker().fix(new Screwdriver()); } }

咱們的Hammer類與Screwdriver類實現這個接口

public class Hammer implements Tools{ public String function(){ return "用錘子修理東西"; } } public class Screwdriver implements Tools{ @Override public String function() { return "用螺絲刀修理東西"; } }

這樣,經過面向接口編程,咱們的代碼就有了很高的擴展性,下降了代碼之間的耦合度,提升了系統的穩定性。

接口隔離原則

接口隔離原則的定義是

客戶端不該該依賴他不須要的接口

換一種說法就是類間的依賴關係應該創建在最小的接口上。這樣說好像更難懂。咱們經過一個例子來講明。咱們知道在Java中一個具體類實現了一個接口,那必然就要實現接口中的全部方法。若是咱們有一個類A和類B經過接口I來依賴,類B是對類A依賴的實現,這個接口I有5個方法。可是類A與類B只經過方法1,2,3依賴,而後類C與類D經過接口I來依賴,類D是對類C依賴的實現可是他們倒是經過方法1,4,5依賴。那麼是必在實現接口的時候,類B就要有實現他不須要的方法4和方法5 而類D就要實現他不須要的方法2,和方法3。這簡直就是一個災難的設計。
因此咱們須要對接口進行拆分,就是把接口分紅知足依賴關係的最小接口,類B與類D不須要去實現與他們無關接口方法。好比在這個例子中,咱們能夠把接口拆成3個,第一個是僅僅由方法1的接口,第二個接口是包含2,3方法的,第三個接口是包含4,5方法的。
這樣,咱們的設計就知足了接口隔離原則。
以上這些設計思想用英文的第一個字母能夠組成SOLID ,知足這個5個原則的程序也被稱爲知足了SOLID準則。

迪米特原則

迪米特原則也被稱爲最小知識原則,他的定義

一個對象應該對其餘對象保持最小的瞭解。

由於類與類之間的關係越密切,耦合度越大,當一個類發生改變時,對另外一個類的影響也越大,因此這也是咱們提倡的軟件編程的總的原則:低耦合,高內聚。
迪米特法則還有一個更簡單的定義

只與直接的朋友通訊。首先來解釋一下什麼是直接的朋友:每一個對象都會與其餘對象有耦合關係,只要兩個對象之間有耦合關係,咱們就說這兩個對象之間是朋友關係。耦合的方式不少,依賴、關聯、組合、聚合等。其中,咱們稱出現成員變量、方法參數、方法返回值中的類爲直接的朋友,而出如今局部變量中的類則不是直接的朋友。也就是說,陌生的類最好不要做爲局部變量的形式出如今類的內部。

這裏咱們能夠用一個現實生活中的例子來說解一下。好比咱們須要一張CD,咱們可能去音像店去問老闆有沒有咱們須要的那張CD,老闆說如今沒有,等有的時候大家來拿就好了。在這裏咱們不須要關心老闆是從哪裏,怎麼得到的那張CD,咱們只和老闆(直接朋友)溝通,至於老闆從他的朋友那裏經過何種條件獲得的CD,咱們不關心,咱們不和老闆的朋友(陌生人)進行通訊,這個就是迪米特的一個應用。說白了,就是一種中介的方式。咱們經過老闆這個中介來和真正提供CD的人發生聯繫。

總結

到這裏,面向對象的六大原則,就寫完了。咱們看出來,這些原則其實都是應對不斷改變的需求。每當需求變化的時候,咱們利用這些原則來使咱們的代碼改動量最小,並且所形成的影響也是最小的。可是咱們在看這些原則的時候,咱們會發現不少原則並無提供一種公式化的結論,而即便提供了公式化的結論的原則也只是建議去這樣作。這是由於,這些設計原則原本就是從不少實際的代碼中提取出來的,他是一個經驗化的結論。怎麼去用它,用好他,就要依靠設計者的經驗。不然一味者去使用設計原則可能會使代碼出現過分設計的狀況。大多數的原則都是經過提取出抽象和接口來實現,若是發生過分的設計,就會出現不少抽象類和接口,增長了系統的複雜度。讓原本很小的項目變得很龐大,固然這也是Java的特性(任何的小項目都會作成中型的項目)

原文:

http://www.cnblogs.com/qifengshi/p/5709594.html

姓名:王柏成 英文名:WbcSky QQ:1477865775 電子郵件:w329357255@126.com
 
 
 
 

(第一篇) 一步一步帶你瞭解linq to Object

 

要想學好linq to object 咱們必需要先學習lambda 表達式,學習lambda 表達式呢咱們必須瞭解匿名函數和匿名類及擴展方法,學習匿名函數,咱們必須學會委託,這是本文的宗旨。下面開始第一步。在第一步開始以前,咱們作點準備工做,創建一個學生類和一個班級類,類結構以下

複製代碼
   public class Student
    {
        public int Id { get; set; }
        public int ClassId { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Study()
        {
            Console.WriteLine("{0} {1}跟着Eleven老師學習.net高級開發", this.Id, this.Name);
        }
    }

    public class Class
    {
        public int Id { get; set; }
        public string ClassName { get; set; }
    }
複製代碼

在準備一個基礎數據類

複製代碼
 public class LinqShow
    {
        /// <summary>
        /// 準備數據
        /// </summary>
        /// <returns></returns>
        public List<Student> GetStudentList()
        {
            #region 初始化數據
            List<Student> studentList = new List<Student>()
            {
                new Student()
                {
                    Id=1,
                    Name="打兔子的獵人",
                    ClassId=2,
                    Age=35
                },
                new Student()
                {
                    Id=1,
                    Name="Alpha Go",
                    ClassId=2,
                    Age=23
                },
                 new Student()
                {
                    Id=1,
                    Name="白開水",
                    ClassId=2,
                    Age=27
                },
                 new Student()
                {
                    Id=1,
                    Name="狼牙道",
                    ClassId=2,
                    Age=26
                },
                new Student()
                {
                    Id=1,
                    Name="Nine",
                    ClassId=2,
                    Age=25
                },
                new Student()
                {
                    Id=1,
                    Name="Y",
                    ClassId=2,
                    Age=24
                },
                new Student()
                {
                    Id=1,
                    Name="小昶",
                    ClassId=2,
                    Age=21
                },
                 new Student()
                {
                    Id=1,
                    Name="yoyo",
                    ClassId=2,
                    Age=22
                },
                 new Student()
                {
                    Id=1,
                    Name="冰亮",
                    ClassId=2,
                    Age=34
                },
                 new Student()
                {
                    Id=1,
                    Name="瀚",
                    ClassId=2,
                    Age=30
                },
                new Student()
                {
                    Id=1,
                    Name="畢帆",
                    ClassId=2,
                    Age=30
                },
                new Student()
                {
                    Id=1,
                    Name="一點半",
                    ClassId=2,
                    Age=30
                },
                new Student()
                {
                    Id=1,
                    Name="小石頭",
                    ClassId=2,
                    Age=28
                },
                new Student()
                {
                    Id=1,
                    Name="大海",
                    ClassId=2,
                    Age=30
                },
                 new Student()
                {
                    Id=3,
                    Name="yoyo",
                    ClassId=3,
                    Age=30
                },
                  new Student()
                {
                    Id=4,
                    Name="unknown",
                    ClassId=4,
                    Age=30
                }
            };
            #endregion
            return studentList;
        }

    }
複製代碼

 

簡單瞭解委託

 

1. 委託是什麼?

其實,我一直思考如何講解委託,才能把委託說得更透徹。說實話,每一個人都委託都有不一樣的看法,由於看問題的角度不一樣。我的認爲,能夠從如下2點來理解:

 (1) 從數據結構來說,委託是和類同樣是一種用戶自定義類型

 (2) 從設計模式來說,委託(類)提供了方法(對象)的抽象。

既然委託是一種類型,那麼它存儲的是什麼數據?

咱們知道,委託是方法的抽象,它存儲的就是一系列具備相同簽名和返回回類型的方法的地址。調用委託的時候,委託包含的全部方法將被執行。

 

2. 委託類型的定義

委託是類型,就好像類是類型同樣。與類同樣,委託類型必須在被用來建立變量以及類型對象以前聲明。

delegate void MyDel(int x);

 

委託類型聲明:

(1) 以deleagate關鍵字開頭。

(2)返回類型+委託類型名+參數列表。

 

3. 聲明委託變量

MyDel del1,del2;

 

4. 初始化委託變量

(1) 使用new運算符

new運算符的操做數的組成以下:

  • 委託類型名
  • 一組圓括號,其中包含做爲調用列表中的第一個成員的方法的名字。方法能夠是實例方法或靜態方法。
del1 = new MyDel( 實例方法名 );
del2 = new MyDel( 靜態方法名 );

(2)使用快捷語法

快鍵語法,它僅由方法說明符構成。之因此能這樣,是由於在方法名稱和其相應的委託類型之間有隱式轉換。

del1 = 實例方法名;
del2 = 靜態方法名;

 

5. 賦值委託

 因爲委託是引用類型,咱們能夠經過給它賦值來改變包含在委託變量中的方法地址引用。舊的引用會被垃圾回收器回收。

MyDel del;
del = 實例方法名; //委託初始化
del = 靜態方法名;//委託從新賦值,舊的引用將被回收

 

6. 委託調用

委託調用跟方法調用相似。委託調用後,調用列表的每一個方法將會被執行。

在調用委託前,應判斷委託是否爲空。調用空委託會拋出異常,這是正常標準調用

if(null != del)
{
     del.Invoke();//委託調用
}

 

 在net 1.1的時代,咱們是使用Invoke()方法類調用委託的。可是微軟在net 2.0 的時候,咱們能夠這麼去調用委託 直接 del();

if(null != del)
{
     del();//委託調用
}

 

 

7. 綜合練習

複製代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
    class Program
    {
        public delegate void meathed1();//1 委託的聲明   委託是一種類型 
        public delegate int meathed2();//2 能夠聲明在類的內部,也能夠聲明在類的外部
        public delegate void meathed3(int id, string name);
        public delegate string meathed4(string msg);
        static void Main(string[] args)
        {
            meathed1 me1 = new meathed1(m1);
            meathed2 me2 = new meathed2(m2);
            meathed3 me3 = new meathed3(m3);
            meathed4 me4 = new meathed4(m4);
            me1.Invoke();
            int result=   me2.Invoke();
            Console.WriteLine(result);
            me3(1, "wbc");
            Console.WriteLine(me4("您吃了嗎"));
            Console.Read();

        }
        public static void m1() {
            Console.WriteLine("我是無參數無返回值的方法");
        }
        public static int m2()
        {
            Console.WriteLine("我是無參數有返回值的方法~~~~~~~~~");
            return 123;
        }
        public static void m3(int id, string name)
        {
            Console.WriteLine($"我是有參數無返回值的方法,id={id},name={name}");
        }
        public static string m4(string sparams)
        {
            Console.WriteLine($"我是無參數無返回值的方法 ,參數{sparams}");
            return "參數返回了";
        }
    }
}
複製代碼

 

8. 多播委託

 多播委託(MulticastDelegate)繼承自 Delegate ,表示多路廣播委託;即,其調用列表中能夠擁有多個元素的委託。實際上,咱們自定義的委託的基類就是 MulticastDelegate。這句話很差理解,繼續往下看

 

當咱們本身寫一個類去繼承Delegate 的時候,開發工具提示我 特殊類型不容許被繼承,估計這是net 惟一一個特殊類型。

 public abstract class myted : Delegate {

        }

 

咱們來看一個案列來使用下多播委託

 meathed1 me1 = new meathed1(m1);
            me1 += m2;
            me1 += m3;
            me1.Invoke();
            me1 -= m2;
            me1();

 

 多播委託:

+= 的時候就是在委託的實例以後加入註冊更多的方法,像一個鏈子,執行的時候按加入的前後順序執行

-=的時候就是在委託的實例以後移除註冊更多的方法。從鏈子的尾部開始匹配,找到一個徹底吻合的移除,沒有找到不會觸發異常。

注:實例方法由於每一次實例地址的引用不一致,因此沒法移除。

 

9. net 框架提供的自帶委託

 

8.1.Func委託類型

Func是有返回值的泛型委託,能夠沒有參數,但最多隻有16個參數,而且必需要有返回值。

 

Func<string, int> funcDelegate = new Func<string, int>();

 

 2.Action委託類型
Action是沒有返回值的泛型委託,能夠沒有參數,但最多隻有16個參數。 

 Action<string, string> method = new Action<string, string>();

 

  關於泛型這裏就不過多介紹了,本人前邊寫了一篇比較詳細。建議你們之後使用委託的時候,儘可能使用net 類庫自帶的委託。

這裏擴展下事件的基本使用,事件就是在委託的實例加上一個event 的關鍵字。因此委託是一種類型,事件就是委託類型的實例。這裏只是擴展,不懂不影響學習linq to object 

 

複製代碼
 public void Meta() {

        }
        public delegate void meathed1();
        public class Cat {
            public event meathed1 met_event;
            public meathed1 mea = new meathed1(m1);

            public void Run() {
                mea += m2;
                mea.Invoke();
                met_event = new meathed1(m1);
                met_event += m2;
                met_event.Invoke();

            }
            public static void m1() {

            }
            public static void m2() {

            }
        }
複製代碼

 

調用方法以下 

   Cat c = new Cat();
            c.mea = Meta;
            c.mea.Invoke();

            // c.met_event = meta;這種寫法是不容許的,只有經過訂閱的方式才容許,以下
            c.met_event += new meathed1(Meta);

 

使用事件和委託的區別咱們一會兒就能區分出來:事件更安全,在類的外部不容許破壞他的原有執行內容,只有在重新訂閱  event關鍵字限制了權限,保證安全

 

匿名方法&lambda表達式

 咱們看了上面的委託,發現寫起來好麻煩,而且用起來特別的不方便,有沒有更簡便的方法呢?可不能夠把咱們的方法寫到委託裏面呢?答案是確定的;這種寫法咱們稱爲匿名方法。寫法以下:

 Action<string> method = new Action<string>(delegate(string name){
                Console.WriteLine(name);
            });
            method.Invoke("wbc");
            Console.Read();

 

 可是這種寫法還不夠簡便,在.net 2.0的時候,咱們發現1.1的時候在頻繁的使用委託,微軟作了很大的改進和更新,新的寫法以下

 Action<string> method = new Action<string>(name =>
                Console.WriteLine(name)
            );
            method.Invoke("wbc");
            Console.Read();

 

 在2.0裏面,咱們去掉了delegate關鍵字,若是子有一個參數的時候,連括號也省略了,用"=>"指向方法體,這個尖叫號等號咱們讀作「goes to」,若是方法只有一句話,連花括號也省略了。參數類型直接就能夠推算出來。看一個複雜的案列

複製代碼
  Func<string,int,string> method = new Func<string, int, string>((name,age) => {
                return $"{name}今年{age}歲了";
            }
                
            );
         string result=   method.Invoke("wbc",0);
            Console.WriteLine(result);
            Console.Read();
複製代碼

其實咱們的匿名方法就是lambda 表達式。

 

匿名類

有了匿名方法必定會有匿名類,在net 3.0的時候纔有的匿名類,咱們看下在沒有匿名類的時候,咱們是如何去寫的。

 object student = new  {
                id=123,
                name="1234"
            };
            Console.WriteLine(student);
            Console.Read();

 

這種寫法只能輸出 「{ id = 123, name = 1234 }」這種結果的Json 數據,而且咱們在程序中不能使用student.id,會報錯。看下匿名寫法

複製代碼
        var model = new
            {
                Id = 1,
                Name = "Alpha Go",
                Age = 21,
                ClassId = 2
            };
            Console.WriteLine(model.Age);
            Console.Read();
複製代碼

 咱們來看下var 關鍵字,其實var 關鍵字就是一個語法糖,咱們沒必要過於在乎,這裏就不過多的演示了,咱們的根本目的是linq to object

  1. 必須在定義時初始化。也就是必須是var s = 「abcd」形式,而不能是以下形式:
   var s;
   s = 「abcd」;//這種寫法是不容許的
  2. 一但初始化完成,就不能再給變量賦與初始化值類型不一樣的值了。
  3. var要求是局部變量。
4. 使用var定義變量和object不一樣,它在效率上和使用強類型方式定義變量徹底同樣。

 這裏在簡要擴展點技術點「dynamic」,dynamic的用法和object差很少,區別是dynamic在編譯的時候才聲明的一個類型,可是本人建議在程序開發中儘可能避開這個關鍵字,後續MVC 中在詳細介紹,dynamic是net 40裏面的關鍵字。

 

擴展方法

 擴展方法必須創建在靜態類中的靜態方法,且第一個參數前邊要加上this 關鍵字,使用擴展方法必須引用擴展方法所在的類的命名空間,若是想要全局使用,能夠不帶命名空間。我的建議程序中的擴展方法儘可能要帶上命名空間。咱們來看下擴展方法的使用

複製代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
    class Program
    {
       
        static void Main(string[] args)
        {

            int? a = null;
            Console.WriteLine(Helper.ToInt(a));//常規寫法輸出
            Console.WriteLine(a.ToInt());//擴展方法輸出
            if ("1qazwsx1qazwsx1qazwsx1qazwsx".ToLengthInCount(16))
            {
                Console.WriteLine("密碼長度應當小於16個字符");
            }
            Console.Read();
        }
        
    }
    public static class Helper
    {
        /// <summary>
        /// 驗證一個數字是否爲空,爲空返回-1
        /// 擴展方法:靜態類裏的靜態方法,第一個參數類型前面加上this
        /// </summary>
        /// <param name="iParameter"></param>
        /// <returns></returns>
        public static int ToInt(this int? iParameter) {
            return iParameter ?? -1;
        }
        /// <summary>
        /// 驗證一個字符串長度是否大指定長度
        ///  
        /// </summary>
        /// <param name="sParameter"></param>
        /// <returns></returns>
        public static bool ToLengthInCount(this string sParameter, int iCount)
        {
            return sParameter.Length >= iCount ?   true : false;
        }
    }
    
}
複製代碼

 這裏簡要說明下,擴展方法的方法名和類內不得方法名相同,會優先選擇類內部的方法,這是以就近原則,去執行的,關於就近原則,請看本人java 相關博客,有介紹

linq to object 

 

1. 什麼是linq to object ?

LINQ即Language Integrated Query(語言集成查詢),LINQ是集成到C#和Visual Basic.NET這些語言中用於提供查詢數據能力的一個新特性。linq to object 就是對象查詢體系。

  注:LINQ(發音爲Link)

 咱們來看一個簡單的列子,用到了咱們前邊準備的兩個類。咱們要取出學生年齡小於30歲的,咱們若是不會linq to object 的寫法以下

 

複製代碼
 LinqShow linq = new LinqShow();
            List<Student> studentList =   linq.GetStudentList();//獲取基礎數據
            List<Student> studentListLessThan30 = new List<Student>();
            foreach (var item in studentList)
            {
                if (item.Age < 30)
                {
                    Console.WriteLine($"name={item.Name},age={item.Age}");
                    studentListLessThan30.Add(item);
                }
            }
            Console.Read();
複製代碼

咱們可不可使用委託去計算呢??

複製代碼
  LinqShow linq = new LinqShow();
            List<Student> studentList =   linq.GetStudentList();//獲取基礎數據
            List<Student> studentListLessThan30 = new List<Student>();
            //Func<Student, bool> predicate = s => s.Age < 30;//寫法一,
            //var list = studentList.Where<Student>(predicate);//linq 

            var list = Enumerable.Where(studentList, s => s.Age < 30);//使用lambda 表達式寫法
            foreach (var item in list)
            {
                Console.WriteLine($"Name={item.Name} Age={item.Age}");
            }
            Console.Read();
複製代碼

兩段代碼我就不比較了,這裏咱們只來剖析下 studentList 的Where方法,咱們能夠轉移到定義看下,其實where 裏面的參數,以下圖

  咱們會發現,這不List<T>自帶的一個方法,而是一個擴展方法,這個擴展方法在」System.Linq「命名空間的「public static class Enumerable」類下,也就是說根據擴展方法的特色,咱們只要引用了「System.Linq」命名空間,就能使用這個擴展方法,這個擴展方法真的第二個參數是一個Func<TSource, bool> 委託,這個委託有一個TSource泛型參數,一個bool返回值。這就說明了咱們上面的lambda 表達式是成立的。

   繼續剖析,咱們接受的時候,沒有使用List<Student>接收返回的集合,這是由於咱們的linq 只有遇到循環的時候或遇到ToList<T>()的時候纔會去迭代,這裏涉及到迭代器的問題,後續咱們會詳細講解迭代器的使用,或者你們去網上查詢下設計模式迭代器。這麼說,咱們很難理解。咱們經過一個案列來分析,本身寫一個for 循環的擴展方法,對比下

複製代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
    class Program
    {
       
        static void Main(string[] args)
        {
            LinqShow linq = new LinqShow();
            List<Student> studentList =   linq.GetStudentList();//獲取基礎數據
            //var list = Enumerable.Where(studentList, s => s.Age < 30);//使用lambda 表達式寫法,
            Console.WriteLine($"-------------------------linq寫法-----------------------------------");
            var list = studentList.Where( s => {
                Console.WriteLine($"個人年齡是{s.Age}");
               return s.Age < 30;
            });//使用lambda 表達式寫法,這裏在每一次計算,咱們都輸出一個個人年齡是,這裏再也不使用 Enumerable 去調用where ,反正是擴展方法,用法是同樣的
            foreach (var item in list)
            {
                Console.WriteLine($"Name={item.Name} Age={item.Age}");
            }
            Console.WriteLine($"-------------------------自定義擴展方法寫法-----------------------------------");
            var Wbclist = studentList.WbcWhere(s => {
                Console.WriteLine($"Wbc個人年齡是{s.Age}");
                return s.Age < 30;
            });// 自定義擴展方法寫法 這裏再也不使用 Enumerable 去調用where 
            foreach (var item in Wbclist)
            {
                Console.WriteLine($"Name={item.Name} Age={item.Age}");
            }
            Console.Read();
        }
        
    }
    public static class Helper
    {
        /// <summary>
        /// 自定義擴展方法計算集合
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> WbcWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            //常規狀況下數據過濾
            List<TSource> studentListLessThan30 = new List<TSource>();
            foreach (var student in source)
            {
                //if (item.Age < 30)
                if (predicate(student))
                {
                    studentListLessThan30.Add(student);
                }
            }
            return studentListLessThan30;


        }
        /// <summary>
        /// 驗證一個數字是否爲空,爲空返回-1
        /// 擴展方法:靜態類裏的靜態方法,第一個參數類型前面加上this
        /// </summary>
        /// <param name="iParameter"></param>
        /// <returns></returns>
        public static int ToInt(this int? iParameter) {
            return iParameter ?? -1;
        }
        /// <summary>
        /// 驗證一個字符串長度是否大指定長度
        ///  
        /// </summary>
        /// <param name="sParameter"></param>
        /// <returns></returns>
        public static bool ToLengthInCount(this string sParameter, int iCount)
        {
            return sParameter.Length >= iCount ?   true : false;
        }
    }
    
}
複製代碼

咱們來看下輸入結果

 

經過執行結果,咱們會發現,自定義的擴展方法是循環一遍,統一輸出的,沒有延遲,而linq 的寫法有延遲。這也就是咱們linq 核心之一 「linq 是有延遲的」。這裏特別說明,linq 的延遲加載和EF ,ORM 的延遲加載,不是一會事,這裏說的延遲,指的是當用到某條數據的時候,纔會去查詢。

2. 高逼格裝X時刻

咱們以llambda表達式去寫linq 稱爲 查詢運算符寫法,下邊咱們 使用 查詢表達式去寫,注意區分什麼是查詢表達式,什麼是查詢運算符寫法,我面試的不少人都說反了。

案列一 多條件過濾篩選數據

複製代碼
  LinqShow linq = new LinqShow();
            List<Student> studentList =   linq.GetStudentList();//獲取基礎數據
                //查詢運算符
                var list1 = studentList.Where<Student>(s => s.Age < 30 && s.Name.Length > 3);//陳述句
                foreach (var item in list1)
                {
                    Console.WriteLine("Name={0}  Age={1}", item.Name, item.Age);
                }
             
                //查詢表達式
                Console.WriteLine("********************");
                var list2 = from s in studentList
                           where s.Age < 30 && s.Name.Length > 3
                           select s;
                foreach (var item in list2)
                {
                    Console.WriteLine("Name={0}  Age={1}", item.Name, item.Age);
                }
             
            Console.Read();
複製代碼

 咱們會發現,表達式的寫法是否是很像sql ,語法以from  對象 ... in .. where  select 對象  ,是否是很高大上,夠逼咯吧!!!!!!,下邊在簡單介紹幾個案列

案列二將篩選數據付給匿名類或者實體類

複製代碼
 {
                    Console.WriteLine("********************");
                    var list = studentList.Where<Student>(s => s.Age < 30)
                                         .Select(s => new
                                         {
                                             IdName = s.Id + s.Name,
                                             ClassName = s.ClassId == 2 ? "高級班" : "其餘班"
                                         });
                    foreach (var item in list)
                    {
                        Console.WriteLine("Name={0}  Age={1}", item.ClassName, item.IdName);
                    }
                }
                {
                    Console.WriteLine("********************");
                    var list = from s in studentList
                               where s.Age < 30
                               select new
                               {
                                   IdName = s.Id + s.Name,
                                   ClassName = s.ClassId == 2 ? "高級班" : "其餘班"
                               };

                    foreach (var item in list)
                    {
                        Console.WriteLine("Name={0}  Age={1}", item.ClassName, item.IdName);
                    }
                }
複製代碼

 

案列三 排序分頁

複製代碼
   var list = studentList.Where<Student>(s => s.Age < 30)
                                         .Select(s => new
                                         {
                                             Id = s.Id,
                                             ClassId = s.ClassId,
                                             IdName = s.Id + s.Name,
                                             ClassName = s.ClassId == 2 ? "高級班" : "其餘班"
                                         })
                                         .OrderBy(s => s.Id)//首先升序排序
                                         .OrderByDescending(s => s.ClassId)//首先降序排序
                                         .ThenBy(s => s.ClassId)//升序降序排序之後再排序
                                         .Skip(2)//跳過  分頁
                                         .Take(3)//獲取數據
                                         ;
                    foreach (var item in list)
                    {
                        Console.WriteLine($"Name={item.ClassName}  Age={item.IdName}");
                    }
複製代碼

 

 案列四 關聯查詢

 首先添加班級數據 

複製代碼
 List<Class> classList = new List<Class>()
                {
                    new Class()
                    {
                        Id=1,
                        ClassName="初級班"
                    },
                    new Class()
                    {
                        Id=2,
                        ClassName="高級班"
                    },
                    new Class()
                    {
                        Id=3,
                        ClassName="微信小程序"
                    },
                };
複製代碼

 

 表達式寫法

複製代碼
  var list = from s in studentList
                           join c in classList on s.ClassId equals c.Id
                           select new
                           {
                               Name = s.Name,
                               CalssName = c.ClassName
                           };
                foreach (var item in list)
                {
                    Console.WriteLine($"Name={item.Name},CalssName={item.CalssName}");
                }
複製代碼

 

算數運輸符寫法

複製代碼
  var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                {
                    Name = s.Name,
                    CalssName = c.ClassName
                });
                foreach (var item in list)
                {
                    Console.WriteLine($"Name={item.Name},CalssName={item.CalssName}");
                }
複製代碼

 在linq  中沒有右連接,若是要寫右連接,只能反過來寫,這裏不過多去寫案列了,這種案列網上不少,一會總結事後,分享幾篇

 

總結及推薦

 1.匿名函數只能使用在委託中

2.var 關鍵字的特色,如何使用var 實現匿名類。

3. lambda 表達式

4.擴展方法

5.運算符linq  寫法

6.表達式linq 寫法

7 linq 的延遲加載原理

分享 1 linq 案列 ,很全面的

分享2  linq  標準查詢操做符  很全面的 共五篇

姓名:王柏成 英文名:WbcSky QQ:1477865775 電子郵件:w329357255@126.com
 
 
 
 
 
 
 

10分鐘淺談泛型協變與逆變

 

首先聲明,本文寫的有點粗糙,只讓你瞭解什麼是協變和逆變,沒有深刻研究,根據這些年的工做經驗,發現咱們在開發過程當中,不多會本身去寫逆變和協變,由於自從net 4.0 (Framework 3.0) 之後,.net 就爲咱們提供了 定義好的逆變與協變。咱們只要會使用就能夠。協變和逆變都是在泛型中使用的。

  • 什麼是逆變與協變呢

 

可變性是以一種類型安全的方式,將一個對象當作另外一個對象來使用。若是不能將一個類型替換爲另外一個類型,那麼這個類型就稱之爲:不變量。協變和逆變是兩個相互對立的概念:

 

  • 若是某個返回的類型能夠由其派生類型替換,那麼這個類型就是支持協變
  • 若是某個參數類型能夠由其基類替換,那麼這個類型就是支持逆變的。

 

看起來你有點繞,咱們先準備個「」鳥」類,在準備一個「麻雀」類,讓麻雀繼承鳥類,一塊兒看代碼研究

 

複製代碼
  /// <summary>
    /// 鳥
    /// </summary>
    public class Bird
    {
        public int Id { get; set; }
    }
    /// <summary>
    /// 麻雀
    /// </summary>
    public class Sparrow : Bird
    {
        public string Name { get; set; }
    }
複製代碼

 

 咱們分別取實例化這個類,發現程序是能編譯經過的。

Bird bird1 = new Bird();
Bird bird2 = new Sparrow();
Sparrow sparrow1 = new Sparrow();

  //Sparrow sparrow2 = new Bird();//這個是編譯不經過的,違反了繼承性。

可是咱們放在集合中,去實例化,是沒法經過的

List<Bird> birdList1 = new List<Bird>();

//List<Bird> birdList2 = new List<Sparrow>();//不是父子關係,沒有繼承關係
//一羣麻雀必定是一羣鳥

 那麼咱們如何去實如今泛型中的繼承性呢??這就引入了協變和逆變得概念,爲了保證類型的安全,C#編譯器對使用了 out 和 in 關鍵字的泛型參數添加了一些限制:

  • 支持協變(out)的類型參數只能用在輸出位置:函數返回值、屬性的get訪問器以及委託參數的某些位置
  • 支持逆變(in)的類型參數只能用在輸入位置:方法參數或委託參數的某些位置中出現。
  • 協變

  咱們來看下Net  「System.Collections.Generic」命名空間下的IEnumerable泛型 接口,會發現他的泛型參數使用了out 

如今咱們使用下 IEnumerable  接口來進行一下上述實力,會發現,咱們的泛型有了繼承關係。

IEnumerable<Bird> birdList1 = new List<Bird>();

IEnumerable<Bird> birdList2 = new List<Sparrow>();//協變
//一羣麻雀必定是一羣鳥

下面咱們來本身定義一個協變泛型接口ICustomerListOut<Out T>,讓 CustomerListOut 泛型類繼承CustomerListOut<Out T> 泛型接口。

代碼以下

複製代碼
    /// <summary>
    /// out 協變 只能是返回結果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ICustomerListOut<out T>
    {
        T Get();

       // void Show(T t);//T不能做爲傳入參數
    }

    /// <summary>
    /// 類沒有協變逆變
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CustomerListOut<T> : ICustomerListOut<T>
    {
        public T Get()
        {
            return default(T);
        }

        public void Show(T t)
        {

        }
    }
複製代碼

 咱們會發現,在泛型斜變的時候,泛型不能做爲方法的參數。咱們用本身定義的泛型接口和泛型類進行實例化試試,咱們會發現編譯經過

ICustomerListOut<Bird> customerList1 = new CustomerListOut<Bird>();//這是能編譯的
ICustomerListOut<Bird> customerList2 = new CustomerListOut<Sparrow>();//這也是能編譯的,在泛型中,子類指向父類,咱們稱爲協變

到這裏協變咱們就學完了,協變就是讓咱們的泛型有了子父級的關係。本文開始的時候,協變和逆變,是在C# 4.0 之後纔有的,那C# 4.0之前咱們是怎麼寫的呢,那個時候沒有協變?

老版本的寫法

  List<Bird> birdList3 = new List<Sparrow>().Select(c => (Bird)c).ToList();//4.0之前的寫法

等學完逆變,本文列出C# 4.0 之後的版本 中framework 已經定義好的協變、逆變 泛型接口,泛型類,泛型委託。

  • 逆變

 剛纔咱們學習了泛型參數用out 去修飾,餃子協變,如今來學習下逆變,逆變是使用in來修飾的

這裏就是Net 4.0 給咱們提供的逆變寫法

咱們本身寫一個逆變的接口  ICustomerListIn<in T> ,在寫一個逆變的 泛型類 CustomerListIn<T>:ICustomerListIn<T> ,代碼以下

複製代碼
    /// <summary>
    /// 逆變
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ICustomerListIn<in T>
    {
        //T Get();//不能做爲返回值

        void Show(T t);
    }

    public class CustomerListIn<T> : ICustomerListIn<T>
    {
        public T Get()
        {
            return default(T);
        }

        public void Show(T t)
        {
        }
    }
複製代碼

 

 逆變的泛型參數是不能做爲泛型方法的返回值的,咱們來看下實例化鳥類,和麻雀類,看好使很差使。

ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>();//父類指向子類,咱們稱爲逆變

ICustomerListIn<Bird> birdList1 = new CustomerListIn<Bird>();
birdList1.Show(new Sparrow());
birdList1.Show(new Bird());

Action<Sparrow> act = new Action<Bird>((Bird i) => { });

 到此咱們就徹底學完了逆變與協變

 

  • 總結

逆變與協變只能放在泛型接口和泛型委託的泛型參數裏面,

在泛型中out修飾泛型稱爲協變,協變(covariant  修飾返回值 ,協變的原理是把子類指向父類的關係,拿到泛型中。
 在泛型中in 修飾泛型稱爲逆變, 逆變(contravariant )修飾傳入參數,逆變的原理是把父類指向子類的關係,拿到泛型中。

  • NET 中自帶的斜變逆變泛型

 序號  類別  名稱
 1  接口  IEnumerable<out T> 
 2 委託  Action<in T>
3 委託 Func<out TResult>
 4  接口 IReadOnlyList<out T> 
 5  接口 IReadOnlyCollection<out T>
     

 各位朋友,若是誰還知道,請留言告知

 

姓名:王柏成 英文名:WbcSky QQ:1477865775 電子郵件:w329357255@126.com
相關文章
相關標籤/搜索