C#高级篇 - 巴曹村霸

1.1. 析构方法

作用:释放对象

 谁在使用:GC垃圾回收期在调用

(就算平时有调用也是间接的调用,通过Close|Dispose等方法)

① using 其实也是编译时编译成try-catch-finally{conn.Dispose();};只是写法上优雅(语法糖)

② 如果该对象有Dispose()就说明是非托管的资源,需要手动释放

③ Close()方法关闭对象,没有完全释放(可复用);Dispose()完全释放对象

垃圾回收机制(有些垃圾无法回收):
 回收非托管资源---Windows窗口句柄、数据库链接、GDI对象、独占文件锁等等对象。 ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor

FileStream,Font,lcon,lmage,Matrix,Object,OdbcDataReader,OleDBDataReader.Pen.

Regex,Socket,StreamWriter,Timer.Tooltip 等.

1--Dispose()需要实现IDisposable接口

2--Close()和Dispose()区别。

3--99%情况下不需要自己编写经典方法


public class  DisposeTest : IDisposable

{

    方式一 语法糖  using(FileStream fs = new FileStream(...))

   #region 方式二 经典方式
   private readonly IntPtr unmanagedResource;//非托管内存

   private readonly SafeHandle manageResource;//托管资源

   public DisposeTest(){

       unmanagedResource = Marshal.AllocHGlobal(sizeof(int));//分配非托管内存

       managedResource = new SafeFileHandle(new IntPtr(), true);//创建托管资源   

   } 

 //模仿 回收非托管资源Socket、FileStream等实现Dispose方法,进行自己处理销毁这些资源

public void Dispose(){

   Dispose(true);//调用处理方法

  GC.SuppressFinalize(this);//让GC忽略

}

protected virtual void Dispose(boolean isManualDisposing){

   ReleaseUnmanagedResource(unmanagerResource);//处理非托管资源

   if(isManualDisposing){

          ReleaseManagedResource(managedResource);//处理托管资源

    }

}

private void ReleaseManagedResource(SafeHandle safeHandle){

  if(safeHandle != null){

     safeHandle.Dispose();

  }

}

private void ReleaseUnmanagedResource(IntPtr intPtr){

   Marshal.FreeHGlobal(intPtr);//释放非托管内存

}

//对象被销毁时,会自动调用析构方法,销毁回收非托管资源

~DisposeAction(){

    Dispose(false);

}

#endregion

}

1.2. 虚方法

关键字:virtual+override

作用:允许子类/派生类重写,去实现不一样的功能

特点: 好维护

1.3. 抽象类

关键字:abstract

定义:一定要写在抽象类里面,而且不能new,不带方法体

使用场景:抽象方法强制性要求子类去实现

① 单继承,接口可以多继承

接口的关键字:interface

② 对象初始化新方式:

Person person = new Person(){

  Age = 20,

 Name = "Ant",

 Phone = "123456"

}

1.4. 自定义泛型

① 快速创建构造方法的快捷方式:Alt + Enter 或 ctrl+.

② 内部对象类用struct结构?

③ 可以通过泛型属性(MyGeneric<int>右键菜单【open code in ILSpy】反编译查看源码)

安装该插件:扩展/管理扩展/联机(搜索ILSpy反编译工具)

④ 泛型的实现底层源码中用MyGeneric占位符=`反单引号(`1<!T>::t),调用时才会塞入真正类型MyGeneric替换掉占位符(`1<int32>::.ctor(!0)) 【这一点java的泛型只是语法糖,只保证安全性】

static void Main(string[] args)

{

//===============泛型自定义==================

  MyGeneric<int> myGeneric = new MyGeneric<int>(1111);

  myGeneric.Show();

//================泛型方法=================

  Show("这是泛型方法");

  Show(888888);//直接根据入参判断泛型类型

//================泛型接口================

Dictionary<TKey, TValue> : IDictonary<Tkey,TValue>,ICollection<KeyValuePair<TKey,TValue>>

}

public static void Show<T>(T t)

{

   Console.WriteLine(t.ToString());

}

class MyGeneric<T>

{

   private T t;

   public MyGeneric(T t){//快捷方式:Alt + Enter 或 ctrl+.

      this.t =t;

   }

   public  void Show(){

      Console.WriteLine(t);

   } 

}

① 点击项目右键【生成】,其实点击顶部工具栏的【启动】也会触发生成(编译过程)

② 生成DLL/EXE文件

1、项目右键【在文件资源管理器中打开文件夹】->项目文件夹下/bin/debug/文件夹下->编译后此处(控制台程序)就会生成exe文件;如果是类库的话,会生成dll文件

③ 需要通过CLR/JIT来继续编译成机器码(0|1)*;exe由中间语言IL构成(类似class字节码文件)

1.5. C#泛型的约束

泛型约束where T:XX

[1] new()约束--表示T类型只接收带有一个无参数的构造函数

[2] struct值类型约束(show<T>(T t) where T:struct)

[3] class引用类型约束

[4]自定义类型约束(show<T>(T t) where T:Student)(基类型约束、接口类型约束),基类约束,只能有一个而且要放前面(where D:Student,Student2❌,IStudent);接口约束可以有多个

值类型 --- 结构类型struct、int、double、bool、枚举

引用类型 -- 数组、类、接口、委托、object、字符串

① int i = new int();//怀疑int也是自身的包装类

② show<T>(T t) where T:class,new()这种写法也是可以的,同一个参数有多重约束(属于无参构造方法的类)

③ new() 约束一定要写在最后面

④ 多个泛型类型支持写对各个泛型约束(Show(T,S,K,D)(T t)

where D:IStudent

where K:Student

where S:struct

where T:class,new())

⑤ 对于类而言,泛型约束:class Student<T> : Student2 where T:new()

static void Main(string[] arg){

  Student student = new Student();

  IStudent student1 = null;

  Show(student1); ❌ //只能接收入参是(带无参数的构造函数)的类

  Show(student);

}

//约束--表示T类型只接收带一个无参数的构造函数(where T:new()  或 where T:Student)

public static void Show<T>(T t) where T:new()

{

   Console.WriteLine(t);

}

interface IStudent<T>(){//泛型接口

}

//类的泛型约束

class Student<T> : Student2 where T:new() //普通类

{

     //默认有一个无参数的构造

}

class Student2 //普通类

{

     //默认有一个无参数的构造

}

1.6. 协变和逆变

逆变(父类转子类)、协变(子类转父类)

List<People> peoples =new List<People>();

① 其实从现实 中理解 他应该正确才对,但是List<People>类型和 List<Teacher>不是一个类型,从类型的角度来不成立,所以其实这个是语法规则不支持。.net2.0没有,3.0的时候才有协变和逆变

② 协变和逆变它是针对泛型接口和泛型委托来说的,离开了它们就没有这个说法

③ out关键字代表是协变(子->父),in代表是逆变(父->子)

④ 什么情况下使用?在知道自己或别人以后有用到父类通过子类实例化,或子类通过父类实例化的情况下可以用out 或in 关键字

//List<People> peoples1 = new List<Teacher>():


IListOut<People> listOut = new ListOut<People>();

IListOut<People>listOut1 = new ListOut<Teacher>();//协变


IListlN<Teacher> listiN = new ListlN<Teacher>();

IListlN<Teacher> listiN1 = new ListIN<People>();//逆变


lOutintList<Teacher, People> myList1 = new OutlntList<Teacher, People>();

lOutintList<Teacher, People> myList2 = new OutintList<Teacher, Teacher>();/协变lOutintList<Teacher, People> myList3 = new OutintList<People, People>();//逆变l0utintList<Teacher, People> myList4 = new OutlntList<People, Teacher>();//逆变(父类转子类)+协变(子类转父类)

///<summary>

/// 协变只能返回结果,不能做参数(派生类转父类!)

///</summary>

///<typeparam name="T"></typeparam>

interface IListOut<out T>

{

  T GetT();

class ListOut<T>:IListOut<T>

{

  public T GetT(){

      return default(T);//default关键字,如果是值类型则默认返回0,引用类型默认返回null

  }

}

///<summary>

/// in修饰,逆变后,T只能作为当参数 不能做返回值,
/// </summary>
/// <typeparam name="T"></typeparam>

interface lListIN<in T>

{

    // GetT();

    void show(T t);

}

class ListIN<T> : IListIN<T>

{

   public void Show(T t){

   }

}
 

public interface lOutIntList<in inT, out outT>

{

     void show(inT t);

     outT Get();
     outT Do(inT t);

/// out 只能是返回值 in只能是参数

/// void Show1(outT t)

///inT Get1();

}

//逆变(父类转子类)+协变(子类转父类)

//协变和逆变感觉用处不大,有点诡异。。。T1从People变成了Teacher?不知道有何意义

public class OutintList<T1, T2>: lOutintList<T1,T2>{

   public void Show(T1 t)//逆变作为参数

   {  }
   public T2 Get()//协变作为返回值
   {return default(T2);}
   public T2 Do(T1 t)
   {return default(T2);}

}

2.1. 反射 Reflection

类似用来操作metadata元数据的工具

DLL/EXE文件内部包含元数据(metadata) 和中间语言(IL)

① metadata(元数据) 是DLL/exe的一个数据清单(类、方法、特性、属性字段)

② 当前项目/bin/Debug/xx.interface.pdb是编译调试用的文件

③ exe / dll (主要区别就是exe文件有main方法,可执行)

④ 通过JIT去读取元数据metadata,编译成机器码文件;另外还有反射的方式也可以读取元数据

用途 》》:

【1】更新程序时(更新自己的DLL)
【2】使用别人的DLL文件(这种可以读取别人的私有的东西)

 反射是什么? 它就是一个操作metadata的一个类库(可以把反射当成一个小工具用来读取或者操作元数据的)

类、方法、特性、属性字段。(为什么要通过反射间接去操作,1--因为我们需要动态,2--读取私有的对象)

 那些地方使用到了:  asp.net MVC ----ORM---LOC---AOP 几乎所有裤架都会使用反射!!!

///</summary>

2.1.1. 反射使用说明

三种方式加载:1.dll文件名、2.完整路径、3.完全限定名

① 每个项目都会生成一个dll文件(当前项目/bin/Debug/Interface.dll文件)

② Assembly 可以用来转载 dll文件

③一个项目生成一个dll文件,内部包含多个cs类文件,Assembly.GetTypes()相当于找全部类

namespace Ant.DB.SQLServer

{

  public class SQLServerHelper : lDBHelper
  {

    public SQLServerHelper()

     {

       Console.WriteLine(“{0}被构造”,this.GetType().Name);

     }

      public void Query(){ 
        Console.WriteLine("{0}.Query", this.GetType0.Name);

      }

  }

}

Console.WriteLine("----------------Reflection--------------");
Assembly assembly= Assembly.Load("Ant.DB.SQLServer”);//加载方式一:dll文件名
foreach (var type in assembly.GetTypes())//找所有类型(所有类)

{

   Console.WriteLine(type.Name);

   foreach (var method in type.GetMethods())//类型下面的所有方法

   {

     Console.WriteLine("这是"+method.Name+"方法”);

构造方法要用特殊的方法找

   }

}

Assembly assembly = Assembly.Loadfile(@"C:\Users\Administrator\Desktop\奇艺教程\C#语法进阶\MyReflection\Ant.DB.MySqIbin\Debug\Ant.DB.Interface.dll”);//加载方式二:完整路径

因为是接口的DLL所以不包含object自带的方法(Equals\GetHashCode\GetType\ToString)


Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll");//方法三:完全限定名

2.1.2. 使用反射插件对象(Activator.CreateInstance(Type))

第一种加载方式,需要dll文件名在当前目录里面;

try{

   

   Console.WriteLine("*********UseReflection 使用反射创建对象*******");

   Assembly assembly = Assembly.LoadFrom("Ant.DB.SQLServer.dll”);//【1]加载DLL文件

  Type type = assembly.GetType(”Ant.DB.sQLServer.SQLServerHelper”);//【2】获取类型(要完整类型名称)

  object oDbHelper = Activator.Createlnstance(type);//创建对象

  //SQLServerHelper sqlHelper = new SQLServerHelper();

//转成接口的话,方便后期应用于多个数据库API调用

  IDBHelper dBHelper = oDbHelper as IDBHelper;//类型转换(as转换不报错,类型不对就返回null)

  //IDBHelper dBHelper2 =(lDBHelper)oDbHelper

   dBHelper.Query();

} catch(Exception ex){

  Console.WriteLine(ex.Message);

}

2.1.3. 反射创建对象(带参数的构造函数)

Console.WriteLine("******cotr&Parameter********");

Assembly assembly= Assembly.LoadFrom("Ant.DB.SQLServer.dll”);

Type type = assembly.GetType(Ant.DB.SQLServer.ReflectionTest");

//获取到这个类型下面所有构造方法
foreach(Constructorlnfo ctor in type.GetConstructors()))//获取到所有的构造 方法

{

     Console.WriteLine(ctor.Name);

     foreach(var parameter in ctor.GetParameters()//获取到构造方法的所有参数类型

     {

        Console.WriteLine(parameter.ParameterType);//显示类型名称

      }

}

Console.WriteLine("************创建对象************");
object oCotr1 = Activator.Createlnstance(type);//无参数构造函数

object oCotr2 = Activator.CreateInstance(type, new object[] {"Ant编程"});

object oCotr3 = Activator.Createlnstance(type, new object[] { 123});

object oCotr3 = Activator.Createlnstance(type, new object[] { 123,"ant编程"});


class ReflectionTest {

   

  public ReflectionTest(){

      Console.WriteLine($"这是{this.GetType()}无参数构造函数");

  } 
  public ReflectionTest(string name){

      Console.WriteLine($“这是{this.GetType()}有参数构造函数,类型为{name.GetType()}”);

  }
  public ReflectionTest(int id){
       Console.WriteLine($”这是{this.GetType0}有参数构造函数,类型为{id.GetType0}”);
  }
  public ReflectionTest(int id,string name){

  Console.WriteLine($“这是{this.GetType(}有2个参数构造函数,类型为{id.GetType0}和  {name.GetType0}”);

   }

}
 

2.1.4. 反射创建对象(调用私有构造函数)

Activator.CreateInstance(Type type(反射得到的类信息), boolean nonPublic(true:创建私有的构造函数));//别人不想让你创建对象,用了私有,可以反射绕开

①也可以用反射去破坏单例模式,从而创建多个对象

namespace Ant.DB.SQLServer
{

   public class PrivateCtor{

     

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值