15-01-18 C# 面向对象 13

要进入debug文件,除了右键进入资源管理器之外,也可以在解决方案资源管理器右上方,点击显示全部文件按钮,会列出当前项目的文件列表,把要放的文件放入debug即可;

多态的好处 1,减少代码量 2.屏蔽各个子类之间的差异,写出通用的代码;

C#中的访问修饰符;

public 公开的,公共的

private 私有的,只能在当前类的内部访问

protect 受保护的, 只能在当前类的内部以及该类的子类中访问,

internal 只能在当前项目中访问,在同一项目中,internal和public的访问修饰符是一样的,

protected inrernal  它的权限是protected权限加上internal的权限;

修饰类的访问修饰符只有两个,public internal,如果不写类的访问修饰符,默认是internal,表示只有在当前项目中才能访问这个类,出了这个项目就访问不到了,因此我们为了 让在别的项目里也能访问到这个类的话,我们在建类的时候在类的前面加上public

internal的权限和protected相比,在同一个项目中。Internal的权限要比protected大,但是一旦垮了项目,protected的权限要比internal的权限大,因为不同项目之间依然存在继承关系, internal访问不到了,但是由于继承关系,protected成员依然可以跨项目访问,(跨项目的时候1要添加引用,2要添加命名空间);

在命名空间中定义的元素无法显示的声明为private,protected,protected internal;

类中的成员五个访问修饰符都可以定义;

可访问性不一致,子类的访问权限不能高于父类的访问权限;原因是会暴漏父类的成员;

简单工厂设计模式 设计这个项目的一种方式; 有一个牛人把我们写程序当中经常会遇到的问题,没一个问题都写成了一个解决方案;这一个解决方案就是一个设计模式,有23个设计模式;如果把23种设计模式从头到尾敲一遍就是大牛了, 设计模式帮助我们解决在日常开发中遇到的问题,

简单工厂设计模式最核心的就是工厂,这个工厂最后根据用户的输入来返回一个(笔记本对象),但是用户输入的东西是不知道的,只能给他返回一个父类,但是父类里面装的是子类的对象,

重写父类的方法的时候,子类的方法名字和父类被重写方法的名字是一样的,

public abstract class NoteBook

{   

  public abstract void SayHello();

}

public class Lenovo : NoteBook

{   

  public override void SayHello()   

  {       

    Console.WriteLine("我是联想");

  }

}

public class IBM : NoteBook

  {   

    public override void SayHello()   

     {       

      Console.WriteLine("我是IBM");  

      }

  }

public class Acer : NoteBook

  {   

    public override void SayHello()   

    {       

      Console.WriteLine("我是宏基");

      }

}

public class Dell : NoteBook

  {   

    public override void SayHello()   

     {       

      Console.WriteLine("我是戴尔");   

      }

  }

public class Test

{   

public static NoteBook GetNoteBook(string brand) //简单工厂的核心,根据用户的输入创建对象赋值给父类;其实还有一个核心的还是用抽象类实现了多态;     

 {      

     NoteBook nb = null;      

    switch(brand)

      {      

      case"Lenovo":

        nb = new Lenovo();       

        break;      

      case"IBM":

        nb = new IBM();       

        break;      

       case"Acer":

        nb = new Acer();       

        break;      

      case"Dell":

        nb = new Dell();       

         break;  

    }      

    return nb;                //简单工厂最核心的代码部分;

  }

}

string brand = Console.ReadLine();

NoteBook nb = GetNoteBook(brand);

nb.SayHello();

值类型:int double char decimal bool enum struct

引用类型:string 数组 自定义类 集合 object 接口

值类型在复制的时候,传递的是这个值的本身,

person p1 = new person();

p1.Name = "张三";

person p2 = p1;     

//这行代码表示p1,p2指向同一个对象(p1的new person());现在只要改变p1或者p2的其中任何一个,(p1的new person())其中另外一个值就会变;                    

//简单的说,p1和p2指向同一块内存,这个时候只要改变p1,那么p2也跟着改变,只改变p2,那么p1也跟着改变; p2.Name = "李四"; //把p2变成了李四,那么p1也成了李四; Console.WriteLine(p1.Name); 输出的是"李四";

引用类型在复制的时候,传递的是对这个对象的引用(地址);

person p = new person();

p.Name = "张三";

Test(p);

Console.WriteLine(p.Name);  //p.Name 为李四;

public static void Test(person pp)

{  

 person p = pp;  

 p.Name = "李四";

}

不管是形参还是实参都是实实在在在内存中占空间的,

string s1 = "张三";

string s2 = s1;

s2 = "李四";

Console.WriteLine(s1);  //张三 

虽然是引用类型,但是字符串的不可变性;

Console.WriteLine(s2);  //李四

int number = 10;

TestTwo(number);

Console.WriteLine(number);   //输出10;

public static void TestTwo(int n)

{  

n+=10;

}

int number = 10;

TestTwo( ref number);

Console.WriteLine(number);   //输出20;

public static void TestTwo( ref int n)

{

  n+=10;

}

ref能够把一个变量,以参数的形式带到一个方法中进行改变,再将改变完成后的值带出方法,

ref的原理是把值类型的值传递变为引用传递,使得两个值类型共占一块内存空间(地址);

要看变量在栈上的地址,设个断点,运行,然后在即时窗口输入&变量名,按回车;

序列化:就是将对象转换为二进制;

反序列化:就是将二进制转换为对象,

序列化和反序列化的作用:传输数据;

在网络中不管传输什么内容,先把传输的内容二进制,对方接收到的也是二进制,它需要干另外一件事就是反序列化;把这个二进制 反序列化为对象;

public class Person

{    

  private string _name;       

  public string Name  

     {        

    get{return _name;}        

    set{_name = value} 

     }        

     private int  _age;    

     public int Age;

    {       

     get{return _age;}    

     set{_age = value}   

    }         

     private char  _gender;    

     public char Gender   

    {      

      get{return _gender;}     

      set{_gender = value}   

    }

}

序列化的第一步 1.将这个类标记为可以被序列化的,在一个类的上面写上[Serializable]指示一个类可以被序列化,此类不可以被继承;

只有被[Serializable]标记的类创建出来的对象   才能被序列化;

person p = new person();

p.Name = "张三";

p.Age = 19;

p.Gender = '男';

using(FileStream fsWrite = new FileStream(@"C:UsershhsDesktop1.txt",FileMode.OpenOrCreate,FileAccess.Write))

{    //开始序列化对象   

    BinaryFormatter bf = new BinaryFormatter();  

    bf.Serializa(fsWrite,p);

}

    Console.writeline("序列化成功");

  //反序列化

   Person p;

using(FileStream fsRead = new FileStream(@"C:UsershhsDesktop1.txt",FileMode.OpenOrCreate,FileAccess.Read))

{   

    BinaryFormatter bf = new BinaryFormatter();  

    p = (Person)bf.Deserializa(fsRead);

}

Console.WriteLine(p.Name);

Console.WriteLine(p.Age);

Console.WriteLine(p.Gender);

学一个东西一定要知道它是干嘛用的;

在一个命名空间下不允许定义一个重名的类,也不允许在一个类中定义重名的方法(前提是它们没有重载)

我们有的时候必须要在一个命名空间下定义重名的类,比如三个人共同做一个项目,这时候都要写person类,

public partial class Person

{    

}

public partial class Person

{    

}

//这两个都是person类的一部分,共同组成了person类,这样的话就可以同时对person类进行编程,而且一个部分类的成员在另一个部分类里面全都可以访问;  但是部分类里面不允许有重名的方法(不包括重载)

public sealed class Person   //密封类最大的特点就是不能被继承;但是能继承别的类;

{   

}

重写toString()方法; 如果直接对象.ToString(),那么打印出来的是它的命名空间;

所有的类都能ToString(),因为所有类都直接或间接继承object类,ToString()是object类的方法;

因为子类不能调用父类的抽象方法,但是子类可以调用父类的虚方法,所以ToString()是虚方法,因为我们可以重写它,子类可以重写父类的虚方法;(当然子类也可以重写父类的抽象方法)

public class Person

{  

  public  override string Tostring()

    {  

       return  "Hello World";  

    }

}

重写了Tostring()方法,但是只是Person类的ToString();其他类的ToString()依旧没变;

接口:

public class Person

{  

     public void CHLSS()  

    {    

      Console.WriteLine("我是人类,我可以吃喝");  

    }

}

//public class NBAPlayer

//{

//  public void KouLan()

// {

//     Console.WriteLine("我可以扣篮");

//  }

}

public class Student : Person,IKouLanable

{  

    public void KouLan()  

    {   

      Console.WriteLine("我也可以扣篮");  

    } 

}

//由于Student继承了Person类,因此他可以吃喝,但是同时他也想实现可以扣篮,由于继承具有单根性,不能既继承Person,又继承NBAPlayer,这时候我们可以考虑将NBAPlayer定义成一个接口

public  interface IKouLanable 

//以I开头以able结尾表示一种能力

{  

  void KouLan();

}

定义成接口之后,Student就可以既继承Person,又可以继承NBAPlayer接口了,

一个类继承了接口,必须要实现这个接口的成员,快速实现Alt+shift+F10

什么时候需要用到接口, 1.类需要实现多继承;因为类是不允许多继承的;

接口就是一个规范,能力;

接口:

[public] interface I...able

{  

成员;

}

public interface IFlyable

{  

void Fly(); //比抽象方法更省事;

接口中的成员不允许添加访问修饰符;默认就是public,接口中没有方法体,类中成员不添加默认就是private               

//抽象类中普通的方法可以有方法体,但是抽象函数不可以,但是在接口中不允许写有方法体的成员;               

//接口中不能包含字段;接口不是用来存储数据的,存储数据用类来存,  

string Test();  

string Name  

{    

 get;    //自动属性;  接口中能写方法,但是不能有方法体,属性的本质是get,set方法,因为自动属性没有get,set方法体,因此,接口中可以有自动属性,  

   set;    //get和set本质上也是函数,因此这个自动属性和上面的fly没有区别;

   }

}

private string _name;

public string Name

{  

   get{return _name;}

   set{_name = value;}

}

public int Age

{  

  get;  

      set;

}

自动属性,虽然我们没有给它写字段,但是在编译的时候会自动的给我们生成一个字段; 自动属性和普通属性的区别,一个有字段,有方法体 ;一个没有字段,没有方法体; 自动属性的缺点,不能在属性里面进行值的限定了,不允许写方法体,那么要对值进行限定就要使用构造函数了;各有各的好处; 自动属性本质上是两个函数,

接口中可以有方法和属性,还可以有索引器(索引器还没学过;)这三个东西本质上都是方法;接口中只能有方法;

接口是一种规范,只要一个类继承了一个接口,这个类就必须实现这个接口中所有的成员;

一个类中,去实现接口中的方法,没有override,有override是重写;

为了多态,接口不能被实例化,也就是说,接口不能new(不能创建对象);

抽象类,静态类,接口不能被实例化;抽象类,接口由于没有对方法进行实现,因此即使创建了对象也没有意义; 因此要实现多态的话,要去指向一个子类对象; 

//实现多态的时候,3种方法一般都是父类对象装子类;三种方式都是在继承的基础上实现多态;

IFlyable fly = new Person();

fly.Fly();

public class Person:IFlyable

{  

public void Fly()  

  {    

   Console.WriteLine("人类在飞");  

 }

}

public class Bird:IFlyable

{  

   public void Fly()  

    {    

       Console.WriteLine("鸟类在飞");  

    }

}

public interface IFlyable

   {  

     void Fly();

   }

接口中的成员不能加“访问修饰符”,接口中的成员访问修饰符为public,不能修改;

接口中的成员不能有任何实现,这个很我们的抽象类当中的抽象函数是一样的,(都是光说不做,交给子类去做,接口只是定义了一组未实现的成员);

接口中只能有方法,属性,索引器,事件,这四个本质上都是方法,不能有“字段”和构造函数;不能有字段是因为接口不是用来存储数据的,它表示一种规范,一种能力;

因为接口不能创建对象,因此即使有构造函数没有用

接口与接口之间可以继承,并且可以多继承;类就不能多继承;

public interface M1

{  

  void Test1();

}

public interface M2

{  

  void Test2();

}

public interface M3

 {  

   void Test3();

 }

public interface SuperInterface:M1,M2,M3

{  

}

public class Car : SuperInterface  //继承一个大接口,他所继承的接口都要实现;

{  

   public  void Test1();  

    {   

     }

   public  void Test2();  

    {   

    }

    public  void Test3();  

    {   

     }

}

接口并不能去继承一个类,而类可以继承接口(接口只能继承接口。而类既可以继承接口,也可以继承类)

实现接口的子类必须实现该接口的全部成员;

一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并实现了接口IA,那么语法上A必须写在IA的前面; class MyClass:A,IA{},因为类是单继承的.

说是说面向对象的编程,但是很多情况下其实就是面向接口的编程;

比如说手机中的天气预报,有很多个APP都有天气;但是这些数据源头是中央气象台; 中央气象台对外提供了一个接口,那么我只要实现这个接口中的成员,按照指定的要求去做,那么就可以得到天气信息;

支付宝之前只有淘宝有,很多网站现在都有,因为也实现了接口,所以现在基本上就是面向接口编程;

麻雀会飞, 鹦鹉会飞 鸵鸟不会飞 企鹅不会飞  直升机会飞

用多态来实现虚方法,抽象类,接口;

IFlyable fly = new YingWu()//new MaQue()//new Plane();

fly.Fly();

public class Bird

{  

  public double Wings  

  {    

     get;   

     set;

   }

   public void EatAndDrink()   

   {      

       Console.WriteLine("我会吃喝");   

    }  

  }

public class MaQue:Bird,IFlyable

  {  

     public void Fly()   

     {   

       Console.WriteLine("麻雀会飞");   

     }

 }

public class YingWu:Bird,IFlyable,ISpeakable

  {

     public void Fly()   

      {   

        Console.WriteLine("鹦鹉会飞");  

       }      

    public void Speak()   

    {   

       Console.WriteLine("鹦鹉可以学人类说话");

    }

}

public class TuoBird:Bird

  {  

   }

public class QQ:Bird

  {  

  }

public class Plane:IFlyable

  {  

     public void Fly()

    {  

      Console.WriteLine("直升飞机转动螺旋桨飞行");  

    }

}

public interface IFlyable

   {

      void Fly();

   }

public interface ISpeakable

   {  

    void Speak();

   }

//显示实现接口就是为了解决方法的重名问题;

public class Bird:IFlyable

 {  

     public void fly()  

     {   

        Console.WriteLine("鸟会飞");   

     }  

     void IFlyable.Fly()             //显示实现接口; 不允许加访问修饰符,类中的成员默认是private,接口中默认是public

    {   

      Console.WriteLine("我是接口的飞");    //这个其实跟抽象类一样,调用的是父类的函数,只不过在子类中重写了;  

    }    

  }

public interface IFlyable

 {  

    void Fly();

}

Bird自己的方法和接口中的方法重名了,

IFlyable fly = new Bird();

fly.Fly();           //接口的飞  本质上访问的是接口的Fly,只不过接口的Fly被子类实现了;接口的Fly是public的

Bird bird = new Bird();

bird.Fly();         //自己的飞

在我提供给你的这几个类当中,如果说你能抽象出一个父类,并且父类当中必须写上这几个子类共有的方法,然后你不知道如何去写这个方法,这个时候要用抽象类

反之,抽象出来的父类可以写,还需要创建这个父类的对象,这个时候用虚方法,

如果这几个类里面根本找不出父类,但是它们都有共同的行为,共同的能力,这个时候拿接口实现多态;

比如鸟和飞机没有父类,但是它们都会飞,这个飞只能写成接口,不能写个父类去继承,因为根本提不出父类,

//真的鸭子会游泳, 木头鸭子不会游泳,橡皮鸭子会游泳; 一看到会干什么,能干什么侧重于能力,能力就由接口来做,把真鸭子作为父类,但是不能在父类里面写游泳函数,因为木鸭子不会,不能写抽象方法,因为真的鸭子需要被创建 对象,真鸭子有意义,虚方法也不合适,因为木鸭子不会游泳,所以用接口最合适;

public class RealDuck:ISwimming

{  

    public void Swim()  

   {    

     Console.WriteLine("真的鸭子靠翅膀游泳");  

       }

}

public class MuDuck    

 {  

 }

public class XPDuck:ISwimming    

//不写方法体也不会报错,因为继承于RealDuck了,RealDuck里面有Swim了,但是由于他们游泳的方式不一样,因此没必要继承RealDuck

{  

   public void Swim()  

   {   

    Console.WriteLine("橡皮鸭子漂着游泳");  

      }

}

public interface Iswimming

  {  

     void Swim();

  }

ISwiming swim = new RealDuck()//new XPDuck() ;

swim.Swim();

超市收银管理系统,商品类,仓库类,超市类;

类前面不加访问修饰符,默认是Internal表示同一个项目中可以访问;

第一步,写商品的父类ProductFather;写价格,数量,编号三个自动属性;再写一个父类的构造函数

GUID能够帮助我们产生全世界独一无二的编号,GUID是个结构, Guid.NewGuid().ToString();

第二步,写商品的子类继承父类;写出每个子类的构造函数;

第三部,收银系统中最重要的一个类,仓库类;

存储货物;

List<ProductFather>  list1 = new  List<ProductFather>(); //这样写表示把所有的商品都堆在一堆了,没有体现出分门别类存储商品;所有货物都混在一起,拿的时候不好拿;

List<List<ProductFather>>  list2 = new  List<List<ProductFather>>();//在集合里面又放了一个集合;List<ProductFather>这个是数据的类型;

在给list1添加数据的时候,可以把货物对象直接添加进来,坏处是取得时候很麻烦;取得时候不知道哪个下标是谁;看下标对应的是哪个对象;于是乎我们想到用两个集合;

在给list2添加数据的时候只能添加一个集合进去;其实这个集合就是货架;给list2添加进去的不是商品,而是货架;

不管是list1还是list2其实都是整个仓库;

用list1存数据相当于 把商品直接扔进了仓库,在list2中添加进来的是数据的集合,仓库里的货架是货物的集合,所以往仓库添加数据的时候,先添加货架;

List<ProductFather>  list1 = new  List<ProductFather>();

list1[0] list1[1] list1[2]这些就是货物;//这种不好;

List<List<ProductFather>>  list2 = new  List<List<ProductFather>>();//这段代码创建出了一个仓库;

list2[0] list2[1] list2[2]这些就是货架;    

因为创建仓库的时候已经要有货架了,因此我们要创建仓库类的构造函数;

//list[0]存储宏基笔记本   list[1]存储三星手机   list[2]存储酱油   list[3]存储香蕉

public CangKu()

{  

   list.Add(new List<ProductFather>());  

   list.Add(new List<ProductFather>());  

   list.Add(new List<ProductFather>());  

   list.Add(new List<ProductFather>());  

//如果要1000个对象,就要1000行,但是我们可以通过循环创建;

}

进货:

public void JinPros(string strType,int count)

{  

    for(int i = 0 ;i < count;i++)  

    {   

      switch(strType)    

      {        

         case "Acer":

        list[0].Add(new Acer(Guid.NewGuid().ToString(),1000,"宏基笔记本"));       

        break;    

       case "SangSung":

       list[1].Add(new SangSung(Guid.NewGuid().ToString(),2000,"三星手机"));      

       break;    

        case "JiangYou":

       list[2].Add(new JiangYou(Guid.NewGuid().ToString(),10,"老抽酱油"));    

       break;   

       case "Banana":

     list[2].Add(new Banana(Guid.NewGuid().ToString()20,"大香蕉"));     

       break;   

        }

   }

}

//来货之后,我们首先创建仓库对象,然后创建Getpros方法,往里面放货物;

取货:

public ProductFather[] QuPros(string strType,int count)

{

    ProductFather[] pros = new ProductFather[conut];

     for(int i = 0;i < count; i++)

    {   

     switch(strType)    

     {      

       case:"Acer":      

      pros[i] = list[0][0];     

      list[0].RemoveAt[0];    

      break;       

     case:"SangSung":    

      pros[i] = list[1][0];      

      list[1].RemoveAt[0];   

      break;     

      case:"JiangYou":   

       pros[i] = list[2][0];     

      list[2].RemoveAt[0];    

       break;   

      case:"Banana":      

      pros[i] = list[3][0];      

      list[3].RemoveAt[0];     

      break;   

    }  

  }

    return pros;

}

 List<List<ProductFather>>  list2 = new  List<List<ProductFather>>();//这种存储数据的方式是为了分类;

展示货物,

public void ShowPros()

{  

   foreach(var item in list)

    {     

       Console.WriteLine(item[0].Name    item.count    item[0].Price);  

    }

}

泛型集合嵌套泛型集合的方法,我们以后会经常用到;

List<List<ProductFather>>  list = new  List<List<ProductFather>>();

list是仓库,我们给它添加的是List<ProductFather>货架;

当创建仓库对象的时候,调用构造函数,我们给它创建货架;

public  Cangku()

{  

 List.Add(new List<ProductFather>());

 List.Add(new List<ProductFather>());

 List.Add(new List<ProductFather>());

 List.Add(new List<ProductFather>());

}

第四步 收银

CangKu  ck = new CangKu();//创建仓库对象,会通过仓库的构造函数生成4个货架;但是货架上并没有货物,

public SuperMarket()           //创建超市对象的时候,给超市的货架导入货物;

{  

 ck.JinPros("Acer",1000);

 ck.JinPros("SangSung",1000);  

 ck.JinPros("JiangYou",1000);  

 ck.JinPros("Banana",1000);

}

跟用户交互的过程

public void AskBuying()

{   

  string strType = Console.ReadLine();   

  int count = Convert.Int32(Console.ReadLine());   

  //去仓库取货  

  Product[] pros = ck.Qupros(strType,count)  

  double realMoney = GetMoney(pros);  

 Console.WriteLine("选择打折方式 1-不打折 2-打九折 3-打八五折 4-买300送50 5-买500送100") //通过简单工厂的设计模式根据用户的输入获得一个打折对象;

 CalFather cal = GetCal(input);

 double totalMoney = cal.GetTotalMoney(realMoney);  

  }

public double GetMoney(Product[] pros)

{  

    double realMoney = 0;

    realMoney =  pro[0].price * pros.Length;    //之所以能这么写,是因为我们知道只有一种商品,如果不同种类,那就不能这么写了,  

// for(int i = 0;i < pros.Length;i++)

//  {  

//    realMoney +=pros[i].Price

//   }   

   return  realMoney;

}

//由于打折不固定,我们要提取出来一个打折的父类,打折的父类肯定有一个打折的方法,打折的父类不知道子类如何去打折,所以打折的父类只能提供一个抽象的打折方法,   所以要把父类写成一个抽象类,

abstract  class CalFather

{  

public abstract double GetTotalMoney(double realMoney);

}

class CalNormal:CalFather        //正常情况下不打折

{  

public override double GetTotalMoney(double realMoney)  

{   

  return realMoney;  

  }

}

class CalRate:CalFather       //按折扣率打折

{   

   public double Rate   

  {    

      get;  

      set;  

   }

    public CalRate(double rate)   

  {    

     this.Rate = rate;  

    }

     public override double GetTotalMoney(double realMoney)  

  {   

       return realMoney * this.Rate;  

  }

}

class CalMN:CalFather

  {  

      public double M

      {     

         get;   

         set;  

      }

   public double N   

  {    

      get;    

      set;  

   }

public CalMN(double m,double n)  

   {    

        this.M = m;    

        this.N = n;  

   }   

   public override double GetTotalMoney(double realMoney)  

   {      

       if(realMoney > this.M)    

     {        

           return RealMoney - this.N * (int)(realMoney/this.M);  

      }     

      else    

     {      

            return realMoney;    

      }   

   }

 }

简单工厂设计模式,根据用户的输入返回对象; 根据用户的选择打折方式返回一个打折对象;

public CalFather GetCal(string input)

{  

   CalFather  cal = null;  

    switch(input)  

    {   

       case "1":

       cal = new CalNormal();   

       break;   

       case "2":

       cal = new CalRate(0.9);    

       break;   

       case "3":

       cal = new CalRate(0.85);   

       break;   

       case "4":

       cal = new CalMN(300,50);  

       break;

       case "5":

       cal = new CalMN(500,100);  

       break;  

    }  

    return cal;

}

因为展示货物的方法写在仓库类里面,如果在Main()函数里面只创建仓库对象的话,这个时候仓库只有货架,仓库没有货物,仓库只有在创建超市对象的时候才有货物, 因此在超市类里面写一个方法

public void ShowPros()

{   

   ck.ShowPros();//因此在Main函数中就不用创建仓库对象了,只要直接调用超市的ShowPros就可以了,

}

static void Main (string args[])

{  

    //创建超市对象,   

    SuperMarkrt sm = new SuperMarkrt();  

    sm.ShowPros();

}

//扩展 现在只能买一样物品,把它改成买可以买多个物品;

将密码输入数据库的时候,我们需要对数据库的密码进行加密,不能在数据库里明文保存;

项目中只要涉及到存用户密码,就要给他MD5加密;

把一个字符串转成MD5值这样一个过程,这就是MD5加密;我们就用代码来做;

把字符串加密成MD5这样一个过程是不可逆的,就是说你只能把字符串变成MD5值,不能把MD5值变成字符串;

简单一点的密码生成的MD5值可以解密过来,但是复杂一点的密码生成的MD5值就不能解密出来;

MD5是一个抽象类,不能创建对象,但是我们可以通过它的Create静态方法模拟一个对象出来;并没有创建对象;

public static string GetMD5(string str)

{   

MD5 md5 = MD5.Create(); //创建MD5对象;   

//开始加密,将str转换成字符数组;   

byte[] buffer = Encoding.Default.GetBytes(str);   

//返回一个加密好的字节数组;   

byte[] MD5Buffer = md5.ComputerHash(buffer);   

//字节数组转字符串,理论上有三种,   

//1.将字节数组中每个元素按照指定的编码格式解析成字符串; //pass掉就是我们写的,会产生乱码;   

//2.直接将数组ToString();第二种pass因为转的是命名空间   

//3.将字节数组中每个元素ToString();   

//return Encoding.Default.GetString(MD5Buffer);   

string strNew = "";   

for(int i = 0 ; i < MD5Buffer.Length;i++)   

{     

    strNew += MD5Buffer[i].ToString("x2");   

}   

return strNew; 

//产生的是10进制的一串数字,但是MD5是16进制的;

}

.ToString("x");//在ToString()参数里面加个"x"就能把10进制转化为16进制;

.ToString("x2");//在ToString()参数里面加个"x2"也能把10进制转化为16进制;x2就是使得16进制更整齐,有些地方的0给补起来了;

.ToString();里面有很多参数,具有转格式的作用;

原文地址:https://www.cnblogs.com/hhsfrank/p/4231609.html