zoukankan      html  css  js  c++  java
  • 异常、设计模式、序列化、接口、反射、特性

    1.异常

    /// 1 try catch旨在上端使用,保证对用户的展示
    /// 2 下端不要吞掉异常,隐藏错误是没有意义的,抓住再throw也没意义
    /// 3 除非这个异常对流程没有影响或者你要单独处理这个异常

    2.常用的异常

      2.1与参数有关的异常类:派生自SystemException,用于方法成员传递参数时发生异常

        ArgumentException类:用于处理参数无效的异常。ArgumentNullException类:参数为空。

        FormatException类:用于处理参数格式错误的异常。

      2.2与数组有关的异常:继承自SystemException

        IndexOutOfException类:用于处理下标超出了数组长度所引发的异常。

        ArrayTypeMismatchException类:用于处理在数组中存储了数据类型不正确的元素所引发的异常。

      2.3与IO有关的异常:继承自SystemException

        IOException类:用于处理进行文件输入输出操作时所引发的异常。

      2.4内存溢出有关的异常

        OverFlowException类:用于处理程序逻辑错误造成的死循环异常。

      2.5与算术有关的异常

        ArithmeticException类:用于处理与算术有关的异常,比如0做除数。DivideByZeroException类。

      2.6数据库操作异常类

        DbException类:用于处理所有数据源操作异常类的基类。

        SqlException类:用于处理针对sql数据源的异常,比如数据库链接错误。

    3.异常处理

      3.1“底层方法”将第一次捕获的异常传递给上级调用者进一步详细处理

     1 public static int Update(string sql)
     2 {
     3   SqlConnection conn = new SqlConnection(connString);
     4   SqlCommand cmd= new SqlCommand(sql,conn);
     5   try
     6   {
     7     conn.Open();
     8     return cmd.ExecuteNonQuery();
     9   }       
    10   catch(Exception ex)
    11   {
    12     //此处可以添加日志
    13     throw ex;
    14   }
    15   finally
    16   {
    17     conn.Close();
    18   }
    19 }    
    20 
    21 try catch throw finally
    try catch throw finally

     3.2"中层调用者"可以使用多路捕获异常并封装详细异常信息

      添加具体异常对象,通过判断错误号决定异常的类型。

        1.多路捕获异常不是必须的,只有需要的时候才使用。

        2.可以添加多个catch块。

        3.一定要把Exception类放在最后。

        ex.Number的使用,throw new Exception("********"+ex.Message);

        throw ex;这种未经包装

        throw new Exception("******"+ex.Message);这种稍微包装了一下

        异常一般放在业务逻辑里面,不需要放在界面里面,这样界面捕获后就直接显示。

      3.3异常处理的建议

        3.3.1在代码底层出现问题,不要隐瞒,第一时间终止运行

       3.3.2 UI层直接把异常catch住,底层尽量不要catch异常,有问题直接throw异常

       3.3.3除非能容忍某个异常,那么自己try catch,然后日志,剩下的继续

        如果代码有问题,尽量早可能报错,早可能解决

     4.系统功能较多并且业务复杂时,可以使用三层架构设计项目

      表示UI:界面层

      业务逻辑层BLL:将界面层或数据访问层的部分职责(逻辑代码)分离出来

      数据访问层DAL:主要负责连接读写数据库

      表示层UI、业务逻辑层BLL、数据访问层都需要访问实体层(Models)。

       

     5.项目命名的一般规范

      解决方案      项目名称+Pro

      用户界面层  项目名称

      业务逻辑层  项目名称+BLL  业务逻辑类:实体类名+Manager

      数据访问层  项目名称+DAL  数据访问类:实体类名+Service

      实体对象     一般和数据库实体相同 

    6.理解框架

      作用:支撑、主导

    7.典型两层架构设计原理

      分表示层和数据访问层,表示层由前台开发人员夫负责,主要是和用户交互的界面;数据访问层由后台开发人员负责,主要完成数据库的操作。表示层和数据访问层由实体层连接,分层与实体类无必然联系,实体类只是数据传递的载体,什么时候都可以使用。

    8.关于类库项目

      类库项目专门提供软件的功能模块

      类库项目最终生成的是一个dll文件

      通过封装,类库项目能够很好的与外界协作,安全性高

    9.两层架构项目之间的引用

      数据访问层DAL需引用实体层Models,表示层From需引用数据访问层DAL和实体层Models。

    10.实体对象的可序列化

      10.1实体对象在程序中不断的被传递

        表示层(UI)<——>实体对象Models<——>数据访问层DAL

      10.2序列化与反序列

        序列化:将对象状态转换为可保持或传输的格式的过程,在序列化过程中,对象的公有字段和私有字段以及类的名称(包括包含该类的程序集)都被转化为字节流,然后写入数据流。

        反序列化:将流转化为对象,与序列化结合可轻松地存储和传输数据。

      10.3对象序列化的意义

        10.3.1将对的状态保持在存储媒体中,以便可以在以后重新创建精确的副本。

        10.3.2将对象从一个应用程序域发送到另一个应用程序域,对象序列化以后保证数据传输的稳定和安全。

        实体类Models的前面加   [Serializable]

    11.接口  

      接口又叫接口类,接口也是类

      使用关键字interface定义,接口类名称通常使用I开头

      接口中的属性、方法等,只是做一个声明,没有任何实现

      接口中的属性、方法等,默认都是public。

      方法声明类似于抽象方法

      11.1接口具有强制性,实现接口的类必须实现接口的所有成员

      11.2一个类既可以实现多个接口,也可以同时继承其他类

        通常把父类写在接口的前面,继承了一个类,实现了一个接口

      class Student:Person,IStudent,IComparable{...}

     1 //定义接口
     2     interface IMultiPrinter
     3     {
     4         void Print(string content);
     5         void Copy(string content);
     6         bool Fax(string content);
     7     }
     8 
     9 //类实现接口
    10     class HPMultiPrinter:IMultiPrinter
    11     {
    12         public void Print(string content)
    13         {
    14             Console.WriteLine("惠普打印机正在打印..." + content);
    15         }
    16 
    17         public void Copy(string content)
    18         {
    19             Console.WriteLine("惠普打印机正在复印..." + content);
    20         }
    21 
    22         public bool Fax(string content)
    23         {
    24             Console.WriteLine("惠普打印机正在传真..." + content);
    25             return true;
    26         }
    27     }
    28 
    29 //调用接口
    30         static void Main(string[] args)
    31         {
    32             //使用接口定义,类实现该对象
    33             IMultiPrinter objPrinter = new HPMultiPrinter();
    34             objPrinter.Print("学生成绩表");
    35             objPrinter.Copy("学生信息表");
    36             objPrinter.Fax("老师信息表");
    37             Console.ReadKey();
    38         }
    接口的简单应用实例

    12.接口的实践

      12.1提高团队成员并行开发项目的效率

        接口使用者只关心接口的应用功能,不必关心接口的内部实现

        接口实现者只关心如何实现接口的内部实现,不关心谁使用

      12.2提高系统的可维护性

        当用户的需求改变时,只需要修改接口的实现,系统即可更新

    13.接口总结

      接口的应用场合

        如果某一个功能点需求变化较多,应使用接口保证系统的可扩展性

        如果想实现团队成员的并行开发,可以使用接口来规范对象的使用

      接口编写规范

        接口成员只能是一个声明

        实现接口的类必须全部实现接口中规定的属性、方法

      特别说明

        接口的使用不是必须的,要根据用户的需求来决定

    14.继承多态

      多态的应用大大提高了程序的可扩展性

      继承多态实现的条件:1、父类中必须有抽象方法和虚方法

                2、子类必须重写父类中的抽象方法或虚方法

                3、子类对象必须转换成父类类型去使用

      父类类型作为方法的参数类型,调用时实际传递的是子类的对象

    15.接口多态

      实现接口多态的条件:1、一个接口必须被两个或两个以上类实现

                2、接口实现类必须转换成接口类型去使用

      接口作为方法参数类型,调用时实际传递的是接口实现类的对象

      接口多态在实践中应用最广泛

      通俗来说,同样一个方法(方法声明的是接口类对象),因为传递的对象(传递的是接口的派生类)不一样,执行的过程和结果也不一样,这就是接口多态

     1 //定义接口
     2     interface IMultiPrinter
     3     {
     4         void Print(string content);
     5         void Copy(string content);
     6         bool Fax(string content);
     7     }
     8 
     9 //惠普类
    10     class HPMultiPrinter : IMultiPrinter
    11     {
    12         public void Print(string content)
    13         {
    14             Console.WriteLine("惠普打印机正在打印..." + content);
    15         }
    16 
    17         public void Copy(string content)
    18         {
    19             Console.WriteLine("惠普打印机正在复印..." + content);
    20         }
    21 
    22         public bool Fax(string content)
    23         {
    24             Console.WriteLine("惠普打印机正在传真..." + content);
    25             return true;
    26         }
    27     }
    28 
    29 //佳能类
    30     class JNMultiPrinter : IMultiPrinter
    31     {
    32         public void Print(string content)
    33         {
    34             Console.WriteLine("佳能打印机正在打印..." + content);
    35         }
    36 
    37         public void Copy(string content)
    38         {
    39             Console.WriteLine("佳能打印机正在复印..." + content);
    40         }
    41 
    42         public bool Fax(string content)
    43         {
    44             Console.WriteLine("佳能打印机正在传真..." + content);
    45             return true;
    46         }
    47     }
    48 
    49 //实现多态
    50     class Program
    51     {
    52         static void Main(string[] args)
    53         {
    54             Print(new HPMultiPrinter());
    55             Print(new JNMultiPrinter());
    56             Console.ReadLine();
    57         }
    58 
    59         static void Print(IMultiPrinter objPrinter)
    60         {
    61             objPrinter.Print("学生成绩表");
    62             objPrinter.Copy("学生信息表");
    63             objPrinter.Fax("老师信息表");
    64         }
    65     }
    接口多态的简单应用

    16.接口与抽象类

      抽象类 接口
    不同点 用abstract定义 用interface定义
    只能继承一个类 可以实现多个接口
    非抽象派生类必须实现抽象方法 实现接口的类必须实现所有成员
    需要override实现抽象方法 直接实现
    相似点 都不能直接实例化
    都包含未实现的方法
    子类或“接口实现类”必须实现未实现的方法

     17.设计模式与简单工厂

      简单工厂是设计模式中的一种。

       什么是设计模式?设计模式是人们在开发中遇到的共性问题而提出的一个解决方案

               程序开发中的设计模式只是一种参考,而不是一成不变的

      简单工厂:典型应用是解决单一对象创建的扩展问题

      抽象工厂:典型应用是解决多种类型数据库访问问题或不同业务逻辑

      单例模式:典型应用是在开发中设计购物车的时候需使用

    18.简单工厂

      

      实现原理:工厂通过“选择”的方法来指定应该创建哪个“接口实现类的对象”

           “工厂”其实就是一个对象创建的方法,让对象“延迟创建”

      简单工厂创建步骤:

        1、添加接口。

        2、添加需要实现接口的类并实现接口。

        3、添加工厂(建议使用静态类)。
          <1>定义接口变量。
          <2>读取配置文件。
          <3>使用反射创建接口实现类的对象。
          <4>返回接口变量(实际返回的是一个接口实现类的对象)

        4、添加配置文件并配置相应的节点。

        5、调用工厂方法并实现功能。

     1 //接口
     2     /// <summary>
     3     /// 打印接口(产品原型)
     4     /// </summary>
     5     public interface IReport
     6     {
     7         void StartPrint();
     8     }
     9 
    10 //实现接口的类1    
    11     public class ExcelReport:Factory.IReport
    12     {
    13         public void StartPrint()
    14         {
    15             System.Windows.Forms.MessageBox.Show("...正在调用Excel报表程序");
    16         }
    17     }
    18 
    19 //实现接口的类2
    20     public class WordExport:Factory.IReport
    21     {
    22         public void StartPrint()
    23         {
    24             System.Windows.Forms.MessageBox.Show("...正在调用Word报表程序");
    25         }
    26     }
    27 
    28 //工厂类
    29     public class Factory
    30     {
    31         //【1】定义接口变量
    32         static IReport objReport = null;
    33         //【2】读取配置文件
    34         static string reportType = ConfigurationManager.AppSettings["ReportType"].ToString();
    35         //【3】根据配置文件初始化接口变量
    36         public static IReport Choose()
    37         {
    38             switch (reportType)
    39             {
    40                 case "ExcelReport":
    41                     objReport = new ExcelReport();
    42                     break;
    43                 case "WordReport":
    44                     objReport = new WordExport();
    45                     break;
    46                 default:
    47                     break;
    48             }
    49             return objReport;
    50         }
    51     }
    52 
    53 //实现调用代码
    54         private void btn_Print_Click(object sender, EventArgs e)
    55         {
    56             //IReport objReport = new ExcelReport();//new WordReport
    57             //根据工厂提供的具体产品来使用
    58             //这种设计方法,使得调用者和后台实现方法完全脱离,大大增加了系统的可扩展性
    59             IReport objReport = Factory.Factory.Choose();
    60             objReport.StartPrint();
    61         }
    简单工厂的应用

    19.反射 Reflection

      反射的概念

        反射是.NET中的一个重要技术。通过反射,可以在运行时获得某个类型的各种信息,包括方法、属性、事件、及构造函数等,还可以获得每个成员的名称等信息。

      反射的特点

        在程序运行时,动态创建对象、调用方法、设置属性和激励事件,而不是在编译的时候完成。

      反射的应用

        在VS中的智能提示、使用MSIL反汇编工具查看IL代码用的都是反射技术。

        Java开发工具Eclipse中的插件使用,也是用反射技术。

      开发中的应用

        系统需要基于插件开发的时候,必须要用反射。

        在简单工厂和抽象工厂设计模式中将使用反射技术。

        使用反射一般都要配合接口使用。

        反射技术使得系统性能一定程度降低,除非必要情况,反射不宜过多使用。

     1 //1、创建接口类
     2 namespace ICal
     3 {
     4     public interface ICalculator
     5     {
     6         int Add(int a, int b);
     7         int Sub(int a, int b);
     8     }
     9 }
    10 
    11 //2、创建计算器类实现接口
    12 namespace CalDll
    13 {
    14     public class Calculator : ICal.ICalculator
    15     {
    16         public int Add(int a, int b)
    17         {
    18             return a + b;
    19         }
    20 
    21         public int Sub(int a, int b)
    22         {
    23             return a - b;
    24         }
    25     }
    26 }
    27 
    28 //3、使用反射技术应用接口
    29 using System.Reflection;//【1】引入反射命名空间
    30 using ICal;//【2】引入接口类库
    31 
    32         private void btn_Cal_Click(object sender, EventArgs e)
    33         {
    34             //动态加载程序集并创建对象
    35             ICalculator objCal = (ICalculator)Assembly.LoadFrom("CalDll.dll").CreateInstance("CalDll.Calculator");
    36             //通过接口完成运算
    37             int result = objCal.Add(Convert.ToInt16(this.tb_Num1.Text.Trim()), Convert.ToInt16(this.tb_Num2.Text.Trim()));
    38             this.lbl_Result.Text = result.ToString();
    39         }
    用反射技术写了一个计算器应用程序

       反射:System.Reflection  .Net框架提供帮助类库,可以读取并使用metadata。程序可配置可扩展,不需要修改代码,首次运行时读取的。Assembly.Load(Path)这里的path是Debug这个路径下的dll文件名,通过这样并不需要重新引用。IOC,依赖抽象接口,Reflection+Factory+Config

    Console.WriteLine("************************Reflection*****************");
    //【1】 加载dll
    //方式1:dll名称无后缀,从当前目录即Debug加载
    Assembly assembly = Assembly.Load("Ruanmou.DB.MySql");
    //方式2:完整路径的加载  可以是别的目录   加载不会错,但是如果没有依赖项,使用的时候会错
    Assembly assembly1 = Assembly.LoadFile(@"D:MyReflectioninDebugRuanmou.DB.MySql.dll");
    //方式3://带后缀或者完整路径
    Assembly assembly2 = Assembly.LoadFrom("Ruanmou.DB.MySql.dll");
    foreach (var item in assembly.GetModules())
    {
        Console.WriteLine(item.FullyQualifiedName);
    }
    foreach (var item in assembly.GetTypes())
    {
        Console.WriteLine(item.FullName);
    }
    //【2】获取类
    Type type = assembly.GetType("Ruanmou.DB.MySql.MySqlHelper");//2 获取类型信息
    //【3】创建对象
    object oDBHelper = Activator.CreateInstance(type);
    //oDBHelper.Query();//oDBHelper是objec不能调用,但实际上方法是有的   因为编译器不认可所以这句会报错
    //【4】类型转换
    IDBHelper iDBHelper = (IDBHelper)oDBHelper;
    //【5】方法调用
    iDBHelper.Query();
    通过Reflection调用方法的5个步骤及加载反射的3种方式
    Console.WriteLine("************************Reflection+Factory+Config*****************");
    IDBHelper iDBHeler = Factory.CreateHelper();//1/2
    iDBHeler.Query();//可配置可扩展   反射是动态的  依赖的是字符串
    Console.WriteLine("************************Common*****************");
    IDBHelper iDBHelper = new SqlServerHelper();
    iDBHelper.Query();
    使用Factory创建反射对象与通常实例化的比较
    public class ReflectionTest
    {
        #region Identity
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public ReflectionTest()
        {
            Console.WriteLine("这里是{0}无参数构造函数", this.GetType());
        }
    
        /// <summary>
        /// 带参数构造函数
        /// </summary>
        /// <param name="name"></param>
        public ReflectionTest(string name)
        {
            Console.WriteLine("这里是{0} 有参数构造函数", this.GetType());
        }
    
        public ReflectionTest(int id)
        {
            Console.WriteLine("这里是{0} 有参数构造函数", this.GetType());
        }
        #endregion
    }
    
    
    Assembly assembly = Assembly.Load("Ruanmou.DB.SqlServer");
    Type type = assembly.GetType("Ruanmou.DB.SqlServer.ReflectionTest");
    object oReflectionTest1 = Activator.CreateInstance(type);//调用无参数构造函数
    object oReflectionTest2 = Activator.CreateInstance(type, new object[] { 123 });//调用int型构造函数
    object oReflectionTest3 = Activator.CreateInstance(type, new object[] { "123" });//调用string型构造函数
    通过Reflection调用不同构造函数
    public class GenericClass<T, W, X>
    {
        public void Show(T t, W w, X x)
        {
            Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name);
        }
    }
    
    
    Assembly assembly = Assembly.Load("Ruanmou.DB.SqlServer");
    Type type = assembly.GetType("Ruanmou.DB.SqlServer.GenericClass`3");//有几个参数,就占位符+几
    //object oGeneric = Activator.CreateInstance(type);
    Type newType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
    object oGeneric = Activator.CreateInstance(newType);
    通过反射调用泛型
    /// <summary>
    /// 反射测试类
    /// </summary>
    public class ReflectionTest
    {
        #region Method
        /// <summary>
        /// 无参方法
        /// </summary>
        public void Show1()
        {
            Console.WriteLine("这里是{0}的Show1", this.GetType());
        }
        /// <summary>
        /// 有参数方法
        /// </summary>
        /// <param name="id"></param>
        public void Show2(int id)
        {
    
            Console.WriteLine("这里是{0}的Show2", this.GetType());
        }
        /// <summary>
        /// 重载方法之一
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        public void Show3(int id, string name)
        {
            Console.WriteLine("这里是{0}的Show3", this.GetType());
        }
        /// <summary>
        /// 重载方法之二
        /// </summary>
        /// <param name="name"></param>
        /// <param name="id"></param>
        public void Show3(string name, int id)
        {
            Console.WriteLine("这里是{0}的Show3_2", this.GetType());
        }
        /// <summary>
        /// 重载方法之三
        /// </summary>
        /// <param name="id"></param>
        public void Show3(int id)
        {
    
            Console.WriteLine("这里是{0}的Show3_3", this.GetType());
        }
        /// <summary>
        /// 重载方法之四
        /// </summary>
        /// <param name="name"></param>
        public void Show3(string name)
        {
    
            Console.WriteLine("这里是{0}的Show3_4", this.GetType());
        }
        /// <summary>
        /// 重载方法之五
        /// </summary>
        public void Show3()
        {
    
            Console.WriteLine("这里是{0}的Show3_1", this.GetType());
        }
        /// <summary>
        /// 私有方法
        /// </summary>
        /// <param name="name"></param>
        private void Show4(string name)
        {
            Console.WriteLine("这里是{0}的Show4", this.GetType());
        }
        /// <summary>
        /// 静态方法
        /// </summary>
        /// <param name="name"></param>
        public static void Show5(string name)
        {
            Console.WriteLine("这里是{0}的Show5", typeof(ReflectionTest));
        }
        #endregion
    }
    
    
    Console.WriteLine("************************Reflection+Method*****************");
    Assembly assembly = Assembly.Load("Ruanmou.DB.SqlServer");
    Type type = assembly.GetType("Ruanmou.DB.SqlServer.ReflectionTest");
    object oReflectionTest = Activator.CreateInstance(type);
    foreach (var item in type.GetMethods())
    {//遍历所有的方法名
        Console.WriteLine(item.Name);
    }
    //oReflectionTest.Show1();//object不能直接调用方法
    {
        //调用Ruanmou.DB.SqlServer命名空间下ReflectionTest类中void Show1()方法
        MethodInfo method = type.GetMethod("Show1");
        method.Invoke(oReflectionTest, null);
    }
    {
        //调用Ruanmou.DB.SqlServer命名空间下ReflectionTest类中void Show2(int id)方法
        MethodInfo method = type.GetMethod("Show2");
        method.Invoke(oReflectionTest, new object[] { 123 });
    }
    {
        //调用Ruanmou.DB.SqlServer命名空间下ReflectionTest类中static void Show5(string name)
        MethodInfo method = type.GetMethod("Show5");
        //使用Reflection调用静态方法,实例那里可以指定为null,因为static是全局唯一的
        method.Invoke(oReflectionTest, new object[] { "麦田的稻草人" });
        method.Invoke(null, new object[] { "果然" });//等同上句
    }
    {
        //void Show3()
        MethodInfo method = type.GetMethod("Show3", new Type[] { });
        method.Invoke(oReflectionTest, new object[] { });
    }
    {
        //void Show3(int id)
        MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(int) });
        method.Invoke(oReflectionTest, new object[] { 123 });
    }
    {
        //void Show3(string name)
        MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(string) });
        method.Invoke(oReflectionTest, new object[] { "Ant" });
    }
    {
        //void Show3(int id, string name)
        MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });
        method.Invoke(oReflectionTest, new object[] { 234, "W" });
    }
    {
        //void Show3(string name, int id)
        MethodInfo method = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
        method.Invoke(oReflectionTest, new object[] { "W", 234 });
    }
    {
        //用Reflection调用私有方法private void Show4(string name)
        MethodInfo method = type.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic);
        method.Invoke(oReflectionTest, new object[] { "天空之上" });
    }
    通过Reflection调用各种方法,包括有无参数、参数重载、私有方法、静态方法
    namespace Ruanmou.DB.SqlServer
    {
        public class GenericDouble<T>
        {
            public void Show<W, X>(T t, W w, X x)
            {
                Console.WriteLine("t.type={0},w.type={1},x.type={2}", t.GetType().Name, w.GetType().Name, x.GetType().Name);
            }
        }
    }
    
    Assembly assembly = Assembly.Load("Ruanmou.DB.SqlServer");
    Type typeGenericDouble = assembly.GetType("Ruanmou.DB.SqlServer.GenericDouble`1");//泛型类有一个参数<T>
    Type newType = typeGenericDouble.MakeGenericType(new Type[] { typeof(int) });
    object oGeneric = Activator.CreateInstance(newType);
    MethodInfo method = newType.GetMethod("Show");
    MethodInfo methodNew = method.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) });//泛型方法后两个参数<W,X>
    methodNew.Invoke(oGeneric, new object[] { 123, "流浪诗人", DateTime.Now });//<int,string,Datetime>
    通过Reflection调用反射类和反射方法
    namespace Ruanmou.Model
    {
        /// <summary>
        /// 实体
        /// </summary>
        public class People
        {
            public People()
            {
                Console.WriteLine("{0}被创建", this.GetType().FullName);
            }
    
            public int Id { get; set; }
            public string Name { get; set; }
            public string Description;
        }
    }
    
    Assembly assembly = Assembly.Load("Ruanmou.Model");
    Type type = assembly.GetType("Ruanmou.Model.People");
    //以上两句也可以用这句代替  Type type = typeof(People);
    object oPeople = Activator.CreateInstance(type);
    foreach (var prop in type.GetProperties())
    {//遍历所有的属性
        Console.WriteLine(type.Name);
        Console.WriteLine(prop.Name);
        Console.WriteLine(prop.GetValue(oPeople));
        if (prop.Name.Equals("Id"))
        {
            prop.SetValue(oPeople, 234);
        }
        else if (prop.Name.Equals("Name"))
        {
            prop.SetValue(oPeople, "风潇潇");
        }
        Console.WriteLine($"{type.Name}.{prop.Name}={prop.GetValue(oPeople)}");
    }
    foreach (var field in type.GetFields())
    {//遍历所有的字段
        Console.WriteLine(type.Name);
        Console.WriteLine(field.Name);
        Console.WriteLine(field.GetValue(oPeople));
        if (field.Name.Equals("Description"))
        {
            field.SetValue(oPeople, "高级班的新学员");
        }
        Console.WriteLine($"{type.Name}.{field.Name}={field.GetValue(oPeople)}");
    }
    通过Reflection调用属性和字段
    namespace Ruanmou.Model
    {
        /// <summary>
        /// 实体
        /// </summary>
        public class People
        {
            public People()
            {
                Console.WriteLine("{0}被创建", this.GetType().FullName);
            }
            public int Id { get; set; }
            public string Name { get; set; }
            public string Description;
        }
    
        public class PeopleDTO
        {
            public PeopleDTO()
            {
                Console.WriteLine("{0}被创建", this.GetType().FullName);
            }
            public int Id { get; set; }
            public string Name { get; set; }//ShortName  特性
            public string Description;
        }
    }
    
    //【1】先声明初始化一个people对象
    People people = new People();
    people.Id = 123;
    people.Name = "Lutte";
    people.Description = "高级班的新学员";
    
    PeopleDTO peopleDTO_1 = new PeopleDTO()
    {
        Id = people.Id,
        Name = people.Name,
        Description = people.Description
    };//通常可以这样声明一个PeopleDTO硬编码
    
    //【2】利用反射根据Dll和了类名创建类型
    Assembly assembly = Assembly.Load("Ruanmou.Model");
    Type typePeople = assembly.GetType("Ruanmou.Model.People");
    Type typePeopleDTO = assembly.GetType("Ruanmou.Model.People");
    //以上三句可以用下面两句代替
    //Type typePeople = typeof(People);
    //Type typePeopleDTO = typeof(PeopleDTO);
    //【3】创建一个DTO实例
    object peopleDTO = Activator.CreateInstance(typePeopleDTO);
    foreach (var prop in typePeopleDTO.GetProperties())
    {//【4】遍历属性
        object value = typePeople.GetProperty(prop.Name).GetValue(people);
        prop.SetValue(peopleDTO, value);
    }
    foreach (var filed in typePeopleDTO.GetFields())
    {//【5】遍历字段
        object value = typePeople.GetField(filed.Name).GetValue(people);
        filed.SetValue(peopleDTO, value);
    }
    通过Reflection对相同属性和字段的两个类的对象赋值,People与PeopleDTO

       反射优点:动态。面向对象语言是静态的,相对安全的,但很多是写死的。

      反射缺点:写起来复杂、避开编译器的检查(有时有异常)、反射性能差一点(性能优化,空间换时间) 、MVC和EF第一次访问很慢,后面很快

      所有的访问修饰符对于反射都是没用的。

    //需要把YKMDLL.dll放到执行目录Debug下
    namespace YKMDLL
    {
        public class CalaAdd
        {
            /// <summary>
            /// 共有字段
            /// </summary>
            public int addResult;
            /// <summary>
            /// 共有属性
            /// </summary>
            public int FirstNum { get; set; }
            /// <summary>
            /// 共有属性
            /// </summary>
            public int SecondNum { get; set; }
            /// <summary>
            /// 共有方法
            /// </summary>
            /// <returns></returns>
            public int Add()
            {
                return FirstNum + SecondNum;
            }
        }
    }
    
    //【1】加载程序集
    Assembly assembly = Assembly.Load("YKMDLL");
    //【2】遍历程序集下所有类型的所有共有成员(属性、字段、方法)
    foreach (Type type in assembly.GetTypes())
    {
        Console.WriteLine($"**当前类型是{type.Name}");
        foreach (PropertyInfo propInfo in type.GetProperties())
        {//仅遍历共有属性
            Console.WriteLine($"    属性类型:{propInfo.PropertyType}    属性名:{propInfo.Name}");
        }
        foreach (FieldInfo fieldInfo in type.GetFields())
        {//仅遍历共有字段
            Console.WriteLine($"    字段类型:{fieldInfo.FieldType}    字段名:{fieldInfo.Name}");
        }
        foreach (MethodInfo methodInfo in type.GetMethods())
        {//仅遍历共有方法
            Console.WriteLine($"    方法返回值类型:{methodInfo.ReturnType}    方法名:{methodInfo.Name}");
        }
    }
    //【3】获取指定类类型
    Type type_Add = assembly.GetType("YKMDLL.CalaAdd");
    //【4】创建实例
    object obj_Add = Activator.CreateInstance(type_Add);
    //【5】设置属性值
    PropertyInfo prop_AddFirst = type_Add.GetProperty("FirstNum");
    prop_AddFirst.SetValue(obj_Add, 123);
    PropertyInfo prop_AddSecond = type_Add.GetProperty("SecondNum");
    prop_AddSecond.SetValue(obj_Add, 2);
    //【6】执行方法
    MethodInfo method_Add = type_Add.GetMethod("Add");
    int result = Convert.ToInt32(method_Add.Invoke(obj_Add, null));
    Console.WriteLine($"反射方法计算的结果:{prop_AddFirst.GetValue(obj_Add)}+{prop_AddSecond.GetValue(obj_Add)}={result}");
    自己写的反射测试

    20.基于接口设计三层架构

      开发团队协作的保障——指定项目开发规范

        项目命名、模块命名、类编写规范、注释要求...

        数据库设计规范:表的命名、实体属性命名、约束...

        项目开发中协作的形式:垂直分工、并行开发

      垂直分工协作

        任务分工:按功能模块

        技术要求:要求开发人员必须熟悉项目各模块(DAL、BLL、UI)编写方法

        应用场合:中小型项目,且开发团队力量较小

        现实比较:类似于小企业的“作坊式”生产

        人员特点:开发人员的工作贯穿整个项目

      并行开发协作

        任务分工:按层(BLL、DAL、UI)划分

        技术要求:只要求开发人员熟悉项目其中一层(BLL、DAL、UI)的业务和编写方法

        应用场合:大中型项目,且开发团队力量强

        现实比较:类似于大企业的“专业化、流水线”生产

        人员特点:熟悉系统业务的开发人员设计BLL业务层

             熟悉数据库开发的人员设计DAL数据层

             善于设计用户界面的开发人员设计UI

     21.特性

      特性:就是一个类,直接或间接继承自Attribute,一般以Attribute结尾,声明时候可以省略Attribute。特性可以影响程序的运行。使用方法是用中括号,感觉上每一个特性都可以带来对应的功能,例如在一个类前加【Serializable】就表明给可以序列化和反序列化,其实这是一种错觉,实际上特性添加后,编译会在元素内部产生IL,但是无法直接使用,仅会在metadata里面有记录。

    //修饰特性 AttributeTargets指该特性用在哪里,All表示全部;AllowMultiple表示特性是否是多重修饰;Inherited表示使用该特性是否可以被继承下去
    [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
    修饰特性
    //修饰特性 AttributeTargets指该特性用在哪里,All表示全部;AllowMultiple表示特性是否是多重修饰;Inherited表示使用该特性是否可以被继承下去
    [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
    public class CustomAttribute : Attribute
    {
        public CustomAttribute()
        { }
        public CustomAttribute(int id)
        {
            Console.WriteLine("********************");
        }
        public string Description { get; set; }
        public string Remark = null;
        public void Show()
        {
            Console.WriteLine($"This is {nameof(CustomAttribute)}");
        }
        //委托  事件 都没问题
    }
    自定义一个CustomAttribute特性
    [Custom(123, Description = "1234", Remark = "2345")]//方法不行
    public class Student
    {
        [CustomAttribute]
        public int Id { get; set; }
        [Leng(5,10)]//还有各种检查
        public string Name { get; set; }
        [Leng(20, 50)]
        public string Accont { get; set; }
    
        [Custom()]//给【该方法】添加特性
        [return: Custom()]//给【该方法返回值】添加特性
        public string Answer([Custom]string name)//给【该方法参数】添加特性
        {
            return $"This is {name}";
        }
    }
    定义一个Student类去使用CustomAttribute特性
    public class Manager
    {
        public static void Show(Student student)
        {
            //特性本身是没用的,只有通过反射创建特性类,才可以执行特性类中的方法,获取特性类中的属性、字段
            //【1】类特性
            Type type = typeof(Student); //student.GetType();
            if (type.IsDefined(typeof(CustomAttribute), true))//创建特性实例前应先检查有没有,而不是直接创建实例,这样性能高
            {
                //Attribute attribute0 = type.GetCustomAttribute(typeof(CustomAttribute), true);
                //CustomAttribute attribute = (CustomAttribute)attribute0;
                //上面两句等同于下面一句
                CustomAttribute attribute = (CustomAttribute)type.GetCustomAttribute(typeof(CustomAttribute), true);
                Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
                attribute.Show();
            }
    
            //【2】属性特性
            PropertyInfo property = type.GetProperty("Id");
            if (property.IsDefined(typeof(CustomAttribute), true))
            {
                CustomAttribute attribute = (CustomAttribute)property.GetCustomAttribute(typeof(CustomAttribute), true);
                Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
                attribute.Show();
            }
    
            //【3】方法特性
            MethodInfo method = type.GetMethod("Answer");
            if (method.IsDefined(typeof(CustomAttribute), true))
            {
                CustomAttribute attribute = (CustomAttribute)method.GetCustomAttribute(typeof(CustomAttribute), true);
                Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
                attribute.Show();
            }
    
            //【4】方法参数特性
            ParameterInfo parameter = method.GetParameters()[0];
            if (parameter.IsDefined(typeof(CustomAttribute), true))
            {
                CustomAttribute attribute = (CustomAttribute)parameter.GetCustomAttribute(typeof(CustomAttribute), true);
                Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
                attribute.Show();
            }
    
            //【5】方返回值数特性
            ParameterInfo returnParameter = method.ReturnParameter;
            if (returnParameter.IsDefined(typeof(CustomAttribute), true))
            {
                CustomAttribute attribute = (CustomAttribute)returnParameter.GetCustomAttribute(typeof(CustomAttribute), true);
                Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
                attribute.Show();
            }
        }
    }
    CustomAttribute特性的管理

     小结:特性本身是没用的,程序运行的过程中找到特性并加以利用,也就是说没有破坏类型封装的前提下,可以加点额外的信息与行为。不反射就使用不了特性,也就是说特性必须结合反射来使用。任何一个可以生效的特性,都是因为有地方主动使用了的。类使用特性的时候,那个类必须先写好调用特性的代码。

    //第一部分【Demo部分】
    using System;
    using System.Reflection;
    
    namespace YKMAttribute
    {
        // 枚举类型
        public enum UserState
        {
            [Remark("正常")]
            Normal = 0,
            [Remark("冻结")]
            Frozen = 1,
            [Remark("删除")]
            Deleted = 2
        }
    
        //特性类
        public class RemarkAttribute : Attribute
        {
            public RemarkAttribute(string remark)
            {//特性类构造函数
                _remark = remark;
            }
            private string _remark = null;
            public string GetAttributeRemark()
            {//特性类返回remark方法
                return _remark;
            }
        }
    
        //Remark特性管理类
        public static class RemarkManager
        {
            //根据枚举值得到中文含义
            public static string GetRemark(this Enum value)
            {
                Type type = value.GetType();
                FieldInfo filedInfo = type.GetField(value.ToString());
                if (filedInfo.IsDefined(typeof(RemarkAttribute), true))
                {
                    RemarkAttribute attribute = (RemarkAttribute)filedInfo.GetCustomAttribute(typeof(RemarkAttribute), true);
                    //上面这句是下面这两句的合写版
                    //Attribute attribute0 = filedInfo.GetCustomAttribute(typeof(RemarkAttribute), true);
                    //RemarkAttribute attribute1 = (RemarkAttribute)attribute0;
                    return attribute.GetAttributeRemark();
                }
                else
                {
                    return value.ToString();
                }
            }
        }
    }
    
    //第二部分【测试部分】
    static void Main(string[] args)
    {
        //正常应该这样写,静态类静态方法传入一个枚举值
        Console.WriteLine(RemarkManager.GetRemark(UserState.Normal));
        //以下两种用到了扩展方法,注意该方法声明GetRemark(this Enum value)中的this
        Console.WriteLine(UserState.Frozen.GetRemark());
        Console.WriteLine(UserState.Deleted.GetRemark());
        Console.ReadKey();
    }
    特性应用——>>给枚举值添加一个中文描述

    /* 定义一个Syudent类,三个属性
     * 要求1:Name属性长度在5~10
     * 要求2:Address属性长度在20~50
     * 要求3:QQ范围为1001~999999999999
     */ 
    public class Student
    {
        [Length(5,10)]
        public string Name { get; set; }
        [Length(20, 50)]
        public string Address { get; set; }
        [Long(10001, 999999999999)]
        public long QQ { get; set; }
    }
    
    
    /* 抽象特性类
     * 两个特性子类
     * 特性验证管理类(其中包含特性验证方法)
     */
    namespace YKMAttribute
    {
        /* 分析可知Name和Address都是验证长度,QQ是验证范围
         * Name和Address可以共用一个特性指定不同的上下限长度
         * QQ可以用另一个特性指定上下限范围
         * 分析结果:【用一个抽象泛型类,和两个子类泛型类】
         */
    
        //抽象特性类
        public abstract class AbstractValidateAttribute : Attribute
        {
            //抽象特性类的抽象方法
            public abstract bool Validate(object value);
        }
    
        [AttributeUsage(AttributeTargets.Property|AttributeTargets.Field)]
        public class LengthAttribute : AbstractValidateAttribute
        {
            private int _min = 0;
            private int _max = 0;
            public LengthAttribute(int min, int max)
            {
                _min = min;
                _max = max;
            }
            public override bool Validate(object value)
            {
                if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
                {
                    int length = value.ToString().Length;
                    if (length >= _min && length <= _max)
                    {
                        return true;
                    }
                }
                return false;
            }
        }
    
        [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
        public class LongAttribute : AbstractValidateAttribute
        {
            private long _min = 0;
            private long _max = 0;
            public LongAttribute(long min, long max)
            {
                _min = min;
                _max = max;
            }
            public override bool Validate(object value)
            {
                if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
                {
                    long result = 0;
                    if (long.TryParse(value.ToString(), out result))
                    {
                        if (result >= _min && result <= _max)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
        }
    
        //特性验证管理类
        public static class ValidateExtension
        {
            public static bool Validate(this object o)//注意这里有this,扩展方法
            {
                Type type = o.GetType();
                foreach (PropertyInfo info in type.GetProperties())
                {//通过反射遍历所有的属性
                    if (info.IsDefined(typeof(AbstractValidateAttribute), true))
                    {//判断是否有配置该特性的属性
                        //如果有配置该特性的属性,得到该属性所有的AbstractValidateAttribute特性
                        object[] attributeArray = info.GetCustomAttributes(typeof(AbstractValidateAttribute), true);
                        foreach (AbstractValidateAttribute attribute in attributeArray)//在这一步转换的
                        {//遍历所有的特性
                            if (!attribute.Validate(info.GetValue(o)))
                            {//检测该方法,判断该值
                                return false;
                            }
                        }
                    }
                }
                return true;
            }
        }
    }
    
    //测试
    static void Main(string[] args)
    {
        Student stu = new Student()
        {
            Name = "MeTrun",
            Address="银河系太阳系地球村江苏省苏州市昆山市开发区世贸东一号13栋1367室",
            QQ=521256
        };
        Console.WriteLine($"stu合格结果:{stu.Validate()}");
        stu.Name = "唐三";
        Console.WriteLine($"stu修改Name后结果:{stu.Validate()}");
        stu.Name = "MeTrun";
        stu.Address = "水帘洞";
        Console.WriteLine($"stu修改Address后结果:{stu.Validate()}");
        stu.Address = "银河系太阳系地球村江苏省苏州市昆山市开发区世贸东一号13栋1367室";
        stu.QQ = 1119;
        Console.WriteLine($"stu修改QQ后结果:{stu.Validate()}");
        Console.ReadKey();
    }
    特性应用——>>验证属性是否OK

     22.反射、特性、泛型作业

    //(数据库)实体类基类
    public class BaseModel
    {
        public int Id { get; set; }
    }
    
    //用户类
    public class User : BaseModel
    {
        [ChinaName("姓名"),Length(5,10)]
        public string Name { get; set; }
        public string Account { get; set; }
        [ChinaName("密码")]
        public string Password { get; set; }
        [ChinaName("邮箱")]
        public string Email { get; set; }
        public string Mobile { get; set; }
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
        //public int State { get; set; }
        [Column("State"),ChinaName("状态")]
        public int Status { get; set; }
        public int UserType { get; set; }
        public DateTime? LastLoginTime { get; set; }
        public DateTime CreateTime { get; set; }
        public int CreatorId { get; set; }
        public int LastModifierId { get; set; }
        public DateTime LastModifyTime { get; set; }
    }
    
    //公司类
    public class Company : BaseModel
    {
        public string  Name { get; set; }
        public DateTime CreateTime { get; set; }
        public int CreatorId { get; set; }
        public int? LastModifierId { get; set; }//可空
        public DateTime LastModifyTime { get; set; }
    }
    实体类与实体类基类
    /// <summary>
    /// 静态常量类
    /// </summary>
    public class StaticConstant
    {
        /// <summary>
        /// sqlServer数据库连接字符串
        /// </summary>
        public static string SqlServerConnString = ConfigurationManager.ConnectionStrings["Customers"].ConnectionString;
    
        private static string DALTypeDll = ConfigurationManager.AppSettings["DALTypeDLL"];
        /// <summary>
        /// Dll名称(命名空间)
        /// </summary>
        public static string DAlDllName = DALTypeDll.Split(',')[0];
        /// <summary>
        /// 类型名称
        /// </summary>
        public static string DALTypeName = DALTypeDll.Split(',')[1];
    }
    静态常量类
    /// <summary>
    /// 仅修饰属性的特性:列名
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnAttribute:Attribute
    {
        public ColumnAttribute(string name)
        {
            _name = name;    
        }
        private string _name = null;
        public string GetColumnName()
        {
            return _name;
        }
    }
    
    //中文名特性
    public class ChinaNameAttribute:Attribute
    {
        public ChinaNameAttribute(string name)
        {
            _name = name;
        }
        private string _name = null;
        public string GetChinaName()
        {
            return _name;
        }
    }
    映射的特性
    //抽象特性类
    public abstract class AbstractValidateAttribute : Attribute
    {
        //抽象特性类的抽象方法
        public abstract bool Validate(object value);
    }
    
    //Email验证特性
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class EmailAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null
                && Regex.IsMatch(oValue.ToString(), @"^w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$");
        }
    }
    
    //长度验证特性
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class LengthAttribute : AbstractValidateAttribute
    {
        private int _min = 0;
        private int _max = 0;
        public LengthAttribute(int min, int max)
        {
            _min = min;
            _max = max;
        }
        public override bool Validate(object value)
        {
            if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
            {
                int length = value.ToString().Length;
                if (length >= _min && length <= _max)
                {
                    return true;
                }
            }
            return false;
        }
    }
    
    //数值范围验证特性
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class LongAttribute : AbstractValidateAttribute
    {
        private long _min = 0;
        private long _max = 0;
        public LongAttribute(long min, long max)
        {
            _min = min;
            _max = max;
        }
        public override bool Validate(object value)
        {
            if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
            {
                long result = 0;
                if (long.TryParse(value.ToString(), out result))
                {
                    if (result >= _min && result <= _max)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }
    
    //电话验证特性
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class MobileAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null && Regex.IsMatch(oValue.ToString(), @"^[1]+[3,5]+d{9}");
        }
    }
    
    //正则表达式验证特性
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class RegexAttribute : AbstractValidateAttribute
    {
        private string _RegexExpression = string.Empty;
        public RegexAttribute(string regex)
        {
            this._RegexExpression = regex;
        }
    
        public override bool Validate(object oValue)
        {
            return oValue != null && Regex.IsMatch(oValue.ToString(), _RegexExpression);
        }
    }
    验证的特性
    public static class AttributeHelper
    {
        /// <summary>
        /// 判断该属性是否使用Column特性,如果使用Column特性,就返回特性指定的列名,如果未使用,就直接返回列名
        /// </summary>
        /// <param name="prop"></param>
        /// <returns></returns>
        public static string GetColumnName(this PropertyInfo prop)
        {
            if (prop.IsDefined(typeof(ColumnAttribute), true))
            {
                ColumnAttribute attribute = (ColumnAttribute)prop.GetCustomAttribute(typeof(ColumnAttribute), true);
                return attribute.GetColumnName();
            }
            else
            {
                return prop.Name;
            }
        }
    
        //中文名
        public static string GetChinaName(this PropertyInfo prop)
        {
            if (prop.IsDefined(typeof(ChinaNameAttribute), true))
            {
                ChinaNameAttribute attribute = (ChinaNameAttribute)prop.GetCustomAttribute(typeof(ChinaNameAttribute), true);
                return attribute.GetChinaName();
            }
            else
            {
                return prop.Name;
            }
        }
    
        public static bool Validate<T>(this T t) where T : BaseModel
        {
            Type type = t.GetType();
            foreach (PropertyInfo info in type.GetProperties())
            {//通过反射遍历所有的属性
                if (info.IsDefined(typeof(AbstractValidateAttribute), true))
                {//判断是否有配置该特性的属性
                    //如果有配置该特性的属性,得到该属性所有的AbstractValidateAttribute特性
                    object[] attributeArray = info.GetCustomAttributes(typeof(AbstractValidateAttribute), true);
                    foreach (AbstractValidateAttribute attribute in attributeArray)//在这一步转换的
                    {//遍历所有的特性
                        if (!attribute.Validate(info.GetValue(t)))
                        {//检测该方法,判断该值
                            return false;
                            //throw new Exception($"{info.Name}的值{info.GetValue(t)}设置不正确");//throw与return二选一
                        }
                    }
                }
            }
            return true;
        }
    }
    特性帮助类
    public interface IBaseDAL
    {
        //查询Id
        T Find<T>(int id) where T : BaseModel;
    
        //查询列表
        List<T> FindAll<T>() where T : BaseModel;
    
        //更新实体
        void Update<T>(T t) where T : BaseModel;
    
        //实体删除
        void Delete<T>(T t) where T : BaseModel;
    
        //Id删除
        void Delete<T>(int id) where T : BaseModel;
    
        //插入实体
        void Insert<T>(T t) where T : BaseModel;
    }
    接口
    //实现接口的类
    public class BaseDAL: IBaseDAL
    {
        // 泛型访问数据库的方法,用BaseModel约束
        // 用id去查询单个实体
        public T Find<T>(int id) where T : BaseModel
        {
            string sql = $"{TSqlHelper<T>._findSql}{id}";
            List<T> listT = new List<T>();
            using (SqlConnection conn=new SqlConnection(StaticConstant.SqlServerConnString))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                conn.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                listT = ReaderToList<T>(reader);
            }
            return listT.FirstOrDefault();
        }
    
        // 泛型访问数据库的方法,用BaseModel约束
        // 查询出所有数据表的全部数据列表
        public List<T> FindAll<T>() where T : BaseModel
        {
            string sql = $"{TSqlHelper<T>._findAllSql}";
            List<T> listT = new List<T>();
            using (SqlConnection conn=new SqlConnection(StaticConstant.SqlServerConnString))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                conn.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                listT = ReaderToList<T>(reader);
            }
            return listT;
        }
    
        /// <summary>
            /// 显示中文名
            /// </summary>
            /// <typeparam name="T"></typeparam>
        public static void ShowChinaName<T>()
            {
                Type type = typeof(T);
                foreach (PropertyInfo prop in type.GetProperties())
                {
                    if (prop.IsDefined(typeof(ChinaNameAttribute), true))
                    {
                        ChinaNameAttribute attribute = (ChinaNameAttribute)prop.GetCustomAttribute(typeof(ChinaNameAttribute), true);
                        Console.WriteLine($"属性:[{prop.Name}]  中文名:[{attribute.GetChinaName()}]");
                    }
                    else
                    {
                        Console.WriteLine($"属性:[{prop.Name}]  中文名:[null]");
                    }
                }
            }
    
        //更新实体
        public void Update<T>(T t) where T : BaseModel
        {
            if (!t.Validate<T>())//在这里使用特性进行验证
            {
                throw new Exception("数据不正确");
            }
            Type type = typeof(T);
            var props = type.GetProperties().Where(p => !p.Name.Equals("Id"));
            string columns = string.Join(",", props.Select(p => $"[{p.GetColumnName()}]=@{p.GetColumnName()}"));
            var paras = props.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();
            //必须参数化 否则引号?   或者值里面还有引号
            string sql = $"update [{type.Name}] set {columns} where Id={t.Id}";
            using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                cmd.Parameters.AddRange(paras);
                conn.Open();
                int result = cmd.ExecuteNonQuery();
                if (result==0)
                {
                    throw new Exception("更新失败,Update数据不存在");
                }
            }
        }
    
        //实体删除
        public void Delete<T>(T t) where T : BaseModel
        {
            string sql = $"{TSqlHelper<T>._deleteSql}{t.Id}";
            using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                conn.Open();
                int result = cmd.ExecuteNonQuery();
                if (result == 0)
                {
                    throw new Exception("删除失败,Delete数据不存在");
                }
            }
        }
    
        //Id删除
        public void Delete<T>(int id) where T : BaseModel
        {
            string sql = $"{TSqlHelper<T>._deleteSql}{id}";
            using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                conn.Open();
                int result = cmd.ExecuteNonQuery();
                if (result == 0)
                {
                    throw new Exception("删除失败,Delete数据不存在");
                }
            }
        }
    
        //插入实体
        public void Insert<T>(T t) where T : BaseModel
        {
            Type type = typeof(T);
            var props = type.GetProperties().Where(p => !p.Name.Equals("Id"));
            string columns = string.Join(",", props.Select(p => $"[{p.GetColumnName()}]"));
            string values = string.Join(",", props.Select(p => $"@{p.GetColumnName()}"));
            var paras = props.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();
            //必须参数化 否则引号?   或者值里面还有引号
            string sql = $"insert into [{type.Name}] ({columns}) values ({values})";
            using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
            {
                SqlCommand cmd = new SqlCommand(sql, conn);
                cmd.Parameters.AddRange(paras);
                conn.Open();
                int result = cmd.ExecuteNonQuery();
                if (result == 0)
                {
                    throw new Exception("插入失败,Insert数据不存在");
                }
            }
        }
    
        #region 封装的方法
        // 查询一个SqlDataReaser的List集
        private List<T> ReaderToList<T>(SqlDataReader reader) where T : BaseModel
        {
            Type type = typeof(T);
            List<T> listT = new List<T>();
            while (reader.Read())
            {
                //这里得t必须声明在while{}中,如果不是,相当于只声明了一个t,后面每一个t都是对前一个重新赋值。
                T t = (T)Activator.CreateInstance(type);
                foreach (PropertyInfo prop in type.GetProperties())
                {
                    object obj = reader[prop.GetColumnName()];
                    if (obj is DBNull)
                    {
                        obj = null;
                    }
                    prop.SetValue(t, obj);
                }
                listT.Add(t);
            }
            return listT;
        }
        #endregion
    }
    重要:实现接口的类(增查删改)
    //泛型静态缓存
    //可以理解这个类就是管理Sql语句的,因为发现sql语句有很多类似的地方,所以在此利用泛型进行了一些封装
    //但是在实际封装之后发现封装的并不尽人意,查询和更新与插入是不一样的,更新与插入需要参数化
    //即使这里封装了,但在引用的时候还是要再次使用type.GetProperties();
    
    //最终决定能缓存就缓存,不能缓存就算了,所以就果断删除_insertSql和_updateSql
    public class TSqlHelper<T> where T : BaseModel
    {
        public static string _findSql = null;
        public static string _findAllSql = null;
        public static string _deleteSql = null;
        //public static string _updateSql = null;
        //public static string _insertSql = null;
    
        static TSqlHelper()
        {
            Type type = typeof(T);
            //删除仅需要类型
            _deleteSql = $"delete from {type.Name} where Id=";
            //查询需要Id
            var props = type.GetProperties();
            string columns = string.Join(",", props.Select(p => $"[{p.GetColumnName()}]"));
            _findSql = $"select {columns} from [{type.Name}] where Id=";
            _findAllSql= $"select {columns} from [{type.Name}]";
            //更新与插入不需要Id
            //var propsNonId = type.GetProperties().Where(p => !p.Name.Equals("Id"));
            //string columns0 = string.Join(",", propsNonId.Select(p => $"[{p.GetColumnName()}]=@{p.GetColumnName()}"));
            //string columns1 = string.Join(",", propsNonId.Select(p => $"[{p.GetColumnName()}]"));
            //string values = string.Join(",", propsNonId.Select(p => $"@{p.GetColumnName()}"));
            //_updateSql = $"update [{type.Name}] set {columns0} where Id=";
            //_insertSql = $"insert into [{type.Name}] ({columns1}) values ({values})";
        }
    }
    泛型静态缓存
    //简单工厂+配置文件+反射
    public class DALFactory
    {
        static DALFactory()
        {
            Assembly assembly = Assembly.Load(StaticConstant.DAlDllName);
            DALType = assembly.GetType(StaticConstant.DALTypeName);
        }
        private static Type DALType = null;
        public static IBaseDAL CreateInstance()
        {
            return (IBaseDAL)Activator.CreateInstance(DALType);
        }
    }
    简单工厂+配置文件+反射
    /* 仔细分析增删改查方法,发现有很多重复代码,步骤细分如下
     * 【1】连接对象【2】Command对象【3】打开连接【4】个别需要添加参数【5】执行增删改方法【6】返回一个结果
     * 考虑使用泛型解耦,先说不同的地方,每个Command对象的sql语句不同,增删改方法不同,返回结果不同
     * 返回结果不同考虑使用泛型,带返回值的委托,微软已经给我们定义好了——>>Func
     * 代码如下:需要注意的一个地方Command对象
     */
    public T ExecSQL<T>(string sql, Func<SqlCommand, T> func)
    {
        using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
        {
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                try
                {
                    conn.Open();
                    T t = func.Invoke(cmd);
                    return t;
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
    }
    
    private T ExcuteSql<T>(string sql, Func<SqlCommand, T> func)
    {
        using (SqlConnection conn = new SqlConnection(StaticConstant.SqlServerConnString))
        {
            using (SqlCommand command = new SqlCommand(sql, conn))
            {
                conn.Open();
                SqlTransaction sqlTransaction = conn.BeginTransaction();
                try
                {
                    command.Transaction = sqlTransaction;
                    T tResult = func.Invoke(command);
                    sqlTransaction.Commit();
                    return tResult;
                }
                catch (Exception ex)
                {
                    sqlTransaction.Rollback();
                    throw ex;
                }
            }
        }
    }
    
    public T Find<T>(int id) where T : BaseModel
    {
        Type type = typeof(T);
        string sql = $"{TSqlHelper<T>.FindSql}{id};";
        Func<SqlCommand, T> func = new Func<SqlCommand, T>(command =>
           {
               SqlDataReader reader = command.ExecuteReader();
               List<T> list = this.ReaderToList<T>(reader);
               T tnew = list.FirstOrDefault();
               return tnew;
           });
        T t = ExecSQL<T>(sql, func);
        return t;
    }
    
    public List<T> FindAll<T>() where T : BaseModel
    {
        Type type = typeof(T);
        string sql = TSqlHelper<T>.FindAllSql;
        List<T> list = new List<T>();
        Func<SqlCommand, List<T>> func = (command =>
             {
                 SqlDataReader reader = command.ExecuteReader();
                 list = this.ReaderToList<T>(reader);
                 return list;
             });
        list = ExecSQL<List<T>>(sql, func);
        return list;
    }
    
    public void Update<T>(T t) where T : BaseModel
    {
        Type type = typeof(T);
        var propArray = type.GetProperties().Where(p => !p.Name.Equals("Id"));
        string columnString = string.Join(",", propArray.Select(p => $"[{p.GetColumnName()}]=@{p.GetColumnName()}"));
        var parameters = propArray.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();
        string sql = $"UPDATE [{type.Name}] SET {columnString} WHERE Id={t.Id}";
        Func<SqlCommand, int> func = (command =>
          {
              command.Parameters.AddRange(parameters);
              int iResult = command.ExecuteNonQuery();
              return iResult;
          });
        int result = ExecSQL<int>(sql, func);
        if (result==0)
        {
            throw new Exception("Update数据不存在");
        }
    }
    增查删改有重复代码,使用委托解耦

     

     

     

     

        

      

     

  • 相关阅读:
    图论:带花树算法-一般图最大匹配
    图论&数学:最小平均值环
    图论:朱刘算法
    图论&动态规划:虚树
    图论:动态点分治
    图论:平面图的对偶图
    图论:DFS序
    打开页面时,所有节点展开(ztree)
    Vue 常用记录
    Vue v-if and v-for
  • 原文地址:https://www.cnblogs.com/yangmengke2018/p/10877199.html
Copyright © 2011-2022 走看看