在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
相关文章
相关标签/搜索