• .NetFrameWork介绍 枚举 结构复习 位运算(第三天的培训内容)


    • c#与.Net的关系

    c#是一门语言,.Net是一个平台。c#有了.Net这个平台才能更好更全的发挥出所有的功能。

    .Net平台其实就是.NetFrameWork,它主要包含三个部分:1、编译器2、基础类库BCL( bass class Library)3、公共运行库CLR( common language runtime)。

    .NetFrameWork版本主要是2.0,3.0,3.5,4.0,其中3.0,3.5版本用的都是2.0的运行库。相当于2.0,3.0,3.5是一个版本的整体。我们可以到windows/Microsoft.Net/FrameWork/下常看各个版本的文件。发现3.0里面的文件很少,主要是给2.0提供了工作流,WPF,WinsowsCommunicationFundation的技术。3.5里面提供了泛型等类库。4.0则是脱离2.0,3.0,3.5的一个单独的完整的版本。.NetFrameWork4.0向下兼容的条件的前提是:必须同时装上2.0,3.0,3.5。

    • c#的执行过程

    1、编译器接收源代码file.cs生成一个名为程序集的文件(.dl类库文件或者.exe文件)。程序集文件包括:可执行程序的描述,元数据,IL,资源。

     ->元数据就是一个关系表,存储表述类于其他类型信息的数据域关系。

     ->IL (Inermediate Language)也称为 CIL MSIL,.Net平台的汇编代码

    2 CLR中的JIT(Just in Time)会对IL进行及时编译,将其编译成机器码到操作系统上OS(也就是说代码需要执行的时候才编译),编译后进行缓存,若是下一次执行同以代码,就直接从缓存里读取数据。

      所以说,CLR中有两个重要的部分,一个是JIT,需要将中间语言编译成机器码,并对代码进行缓存,以供复用,同时还会做优化代码的工作。另一个是GC,帮助管理内存。

      按照以上:执行时才编译-编译时就缓存的过程执行的语言成为编译型语言,它的优点是:利用缓存,以空间换时间,提高性能,加快运行速度。其中又有GC帮助我们自动管理内存,所以我们不用很担心这样会给程序员带来缓存上的问题。

      其中,垃圾回收器GC(gabbage collector)的执行过程为:当一个对象没有引用指向的时候,系统就会通过调用GC.Collect()回收内存。具体如何回收的呢?

      比喻:内存好比餐厅刚用餐的饭桌,服务员好比是GC.collect(),需要移除不用的盘子,调整还有菜的盘子,然后上新菜。实际上,系统底层维护了一个数据类型(三个固定长度的数组),他们分别为0代,1代,2代,系统会将新创建的对象放在0代上,将0代保留下来的对象放在1代上,当1代满了后,则往2代放,2代满了则系统就崩溃了。

    通过代码观察垃圾回收器

     class Person
        {
        }
        class Program
        {
            static void Main(string[] args)
            {
                Person p1 = new Person();
                Person p2 = new Person();
                Person p3 = new Person();
                Person p4 = new Person();
                p3 = null;
                GC.Collect(0);
            }

    通过设置断点发现

    四个对象的地址相互之间的间隔为12。

    当执行p3=null的时候。p3指向的地址就是0X00000000,这时候P2和P3的内存地址间隔相差为24

    当执行GC.Collect(0)的时候,调用垃圾回收器。发现所有对象的地址重新排布,四个对象的地址相互之间间隔又调整为12

    这就是所谓的压缩算法

    • csc.exe来运行.cs文件

    上图表示:运行CMD后输入E:进入E盘的目录下,使用C:WindowsMicrosoft.NETFrameworkv4.0.30319路径下的 csc.exe运行 E盘下的1.cs文件

    会在E盘目录下生成一个1.exe的可执行文件,然后在cmd里输入1.exe 按下回车键 就会运行代码。

    • 配置环境变量

    右键单击我的计算机-->选择属性-->高级配置-->高级选项卡界面-->环境变量-->系统变量-->Path-->编辑,在路径后面加上一个英文的分号,最后点确定;

    关掉cmd窗口再打开,这样就可以直接在里面敲入csc,回车。

         Microsoft visual studio 2010文件下的 Visual Studio Tools的 Visual Studio 命令提示(2010)不用设置环境变量,就可以省略掉路径

    • c#的反编译

    1.Microsoft Windows SDK Tools IL 反汇编工具生成il

    写一个简单helloWorld程序

    namespace il演示
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("hello world");
            }
        }
    }
    View Code

    启动调试后,生成IL(intermediate Language)。打开Microsoft Visual Studio 2010下的 Microsoft Windows SDK Tools IL 反汇编程序,将helloWorld程序生成的exe文件拖入IL反汇编程序中,就可以看到IL代码

    双击打开Main:void(string[])

    .entrypoint表示方法的入口

    下面的则都是表示入栈出栈。

     2.Microsoft  visual studio2010下的visual studio Tools命令行生成il(ildasm对程序集进行反汇编)

    生成2.il文件和2.res文件。
      ilasm对il代码编译成程序集

    • 方法重载的复习(略,见前几篇博客,)

    我们可以声明带有默认参数的方法来代替方法重载,推荐尽量用默认参数的方法来实现方法重载的功能。

    比如代码

     class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("请输入一个数字");
                Console.WriteLine(ReadInt.Read());
                Console.WriteLine("请输入小于89的数字");
                Console.WriteLine(ReadInt.Read(89));
                Console.WriteLine("请输入一个介于1-100之间的数字");
                Console.WriteLine(ReadInt.Read(1, 101));
                Console.ReadKey();
            }
       
        }
     class ReadInt
        {
          public  static int Read()
            {
               return  Read(int.MinValue, int.MaxValue);
            }
           public static int Read(int max)
            {
                return Read(0, max);
            }
          public  static int Read(int min, int max)
            {
                int num = 0;
                while (true)
                {
                    string str = Console.ReadLine();
                    if (int.TryParse(str,out num))
                    {
                        if (num>=min && num<max)
                        {
                            return num;
                        }
                        else
                        {
                            Console.WriteLine("您输入的数字不在范围之内,请重新输入");
                            continue;
                        }
                    }
                    Console.WriteLine("输入格式错误,请重新输入");
                }
            }
        }
    View Code

    该方法重载可以用默认参数的形式来实现其功能

      static void Main(string[] args)
            {
                Console.WriteLine("请输入一个数字");
                Console.WriteLine(ReadInt(int.MinValue, int.MaxValue));
                Console.WriteLine(ReadInt(max:89));
                Console.ReadKey();
            }
            static int ReadInt(int min=0,int max=100)
            {
                int num = 0;
    
                while (true)
                {
                    string str = Console.ReadLine();
                    if (int.TryParse(str, out num))
                    {
                        if (num >= min && num < max)
                        {
                            return num;
                        }
                        else
                        {
                            Console.WriteLine("输入不在范围内请重新输入");
                            continue;
                        }
                    }
                    Console.WriteLine("输入格式有问题"); 
                }
            }
        }
    View Code
    • 枚举复习

    语法:访问修饰符 enum 枚举名{ 成员1,成员2,成员2}

    默认情况下,成员1转换为int类型为0,成员2对应的int类型为1,成员3对应的int类型为2。

    我们可以手动更改成员对应的数字(可参考c#图解)

    作用:将数字与成员绑定在一起。方便程序员操作。

    例如猜拳游戏 ,我们可以进行优化,即将出拳定义为一个enum枚举类型,enum Fist{石头,剪刀,布}这样就不需要IntToFist()方法了,枚举类型的成员对应的就是整数数字0,1,2

     玩家:Computer

     class Computer
        {
            Random r = new Random();
            public int ShowFist()
            {
                int comSelect = r.Next(1, 4);
                Console.WriteLine("电脑出了一个:{0}",IntToFist(comSelect));
                return comSelect;
    
            }
            private static string IntToFist(int userSelect)
            {
                string fist = "";
                switch (userSelect)
                {
                    case 1: fist = "剪刀"; break;
                    case 2: fist = "石头"; break;
                    case 3: fist = ""; break;
    
                }
                return fist;
            }
        }
    View Code

    玩家:自己

      class Player
        {
            public string  name { get; set; }
            public int ShowFist()
            {
                Console.WriteLine("请问你要出什么拳?1.剪刀2.石头3.布");
                int userSelect = ReadInt(1, 3);
                Console.WriteLine("玩家{0}出了一个:{1}",name,IntToFist(userSelect));
                return userSelect;
            }
            private static string IntToFist(int userSelect)
            {
                string fist = "";
                switch (userSelect)
                {
                    case 1:fist = "剪刀";break;
                        case 2:fist = "石头";break;
                        case 3: fist = ""; break;
                    
                }
                return fist;
            }
            private static int ReadInt(int min,int max)
            {
                while (true)
                {
                    int userSelect = 0;
                    string input = Console.ReadLine();
                    if (int.TryParse(input,out userSelect))
                    {
                        if (userSelect>=min && userSelect<=max)
                        {
                            return userSelect;
                        }
                        else
                        {
                            Console.WriteLine("请输入{0}-{1}之间的数",min,max);
                            continue;
                        }
                    }
                    else
                    {
                        Console.WriteLine("请输入数字");
                        continue;
                    }
                }
            }
        }
    View Code

    裁判

     class Judge
        {
            public void CaiJue(int num1, int num2)
            {
                //剪刀  石头   布
                //1     3   -2
                //2     1   1
                //3     2      1
                if (num1-num2==1 || num1-num2==-2)
                {
                    Console.WriteLine("玩家胜利");
                }
                else if (num1==num2)
                {
                    Console.WriteLine("平局");
                }
                else
                {
                    Console.WriteLine("玩家失败");
                }       
            }
        }
    View Code
     class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Player p = new Player();
                    p.name = "chen an";
                    int num1 = p.ShowFist();
                    Computer c = new Computer();
                    int num2 = c.ShowFist();
                    Judge j = new Judge();
                    j.CaiJue(num1, num2);
    
                    Console.ReadKey(); 
                }
            }
        }
    View Code

    优化后的代码为:

      enum Fist
        {
            石头,
            剪刀,
            布
        }

    玩家:Player(抽象类)

      abstract class Player
        {
            public int Selected
            {
                set;
                get;
            }
         public abstract  void ShowFist(); 
        }
    View Code

    玩家:conmputer继承自Palyer

       class Computer:Player
        {
            public override void ShowFist()
            {
                Random random = new Random();
                Selected=random.Next(3);
                switch (Selected)
                {
                    case 0: Console.WriteLine("对方出一个{0}", (Fist)Selected); break;
                    case 1: Console.WriteLine("对方出一个{0}", (Fist)Selected); break;
                    case 2: Console.WriteLine("对方出一个{0}", (Fist)Selected); break;
                }
            }
        }
    View Code

    玩家:自己继承子Player

    class Self : Player
        {
            public string Name
            {
                set;
                get;
            }
            public Self(string name)
            {
                this.Name = name;
            }
            public override void ShowFist()
            {
               switch (Selected)
                {
                    case 0:Console.WriteLine("{1}出一个{0}",(Fist)Selected,Name);break;
                    case 1: Console.WriteLine("{1}出一个{0}", (Fist)Selected,Name);break;
                    case 2:Console.WriteLine("{1}出一个{0}",(Fist)Selected,Name);break;
                }
            }
        }
    View Code

    玩家:裁判

    class Judg
        {
            public void Caijue(int num1,int num2,string name)
            {
                if (num1-num2==-1 ||num1-num2==2)
                {
                    Console.WriteLine("恭喜{0},你赢了",name);
                }
                else if (num1==num2)
                {
                    Console.WriteLine("{0}你们打平了",name);
                }
                else
                {
                    Console.WriteLine("{0}你又输了",name);
                }
            }
        }
    View Code
    class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("请输入你的名字");
                string str = Console.ReadLine();
               
                while (true)
                {
                    Console.Clear();
                    Console.WriteLine("请出拳,输入0表示为石头,输入1表示为剪刀,输入2表示为布");
    
                    Self s = new Self(str);
                    s.Selected = ReadInt();
                    s.ShowFist();
    
                    Computer c = new Computer();
                    c.ShowFist();
                    Judg j = new Judg();
                    j.Caijue(s.Selected, c.Selected,str);
                    Console.Write("
    按任意键继续");
                    Console.ReadKey();
                }
            }
            static int ReadInt()
            {
                int select;
                while (true)
                {
                    string str=Console.ReadLine();
                    if (int.TryParse(str, out select))
                    {
                        if (select>=0 && select<3)
                        {
                            return select;
                        }
                        else
                        {
                            Console.WriteLine("输入不在范围内,请输入0-2之间的数字");
                            continue;
                        }         
                    }
                    Console.WriteLine("您的输入有误,请重新输入数字");
                }
            }
        }
    View Code

     标志枚举:利用二进制数据中每个数据位上的标志表示一个状态,不同状态可以组合在一起使用逻辑或运算。

    比如 enum 方向{东,南,西,北}

    东   1  0001

    南   2  0010

    西   4  0100

    北   8  1000

    东南可以表示为:0011 0001 |0010

    比如.NetFrameWork中 System.Reflection.BindingFlags就是一个枚举类型,里面用了标志枚举 打开元定义发现

    • 位运算
    class Program
        {
            static void Main(string[] args)
            {
                // 移位元算 <<      >>
              
                int num = 1;
                //    num=1表示为: 0000 0000 0000  0000 0000 0000 0000 0001
                //  <<1  左移运算等价于乘以1的指定次冥
                Console.WriteLine(num<<1);  //结果为2 =1*2的一次方
                Console.WriteLine(num << 2);//结果为3=1*2的二次方
                Console.WriteLine(num);//结果为1;
    
                //  | 或运算  &与元算   ^异或元算  !非运算
                Console.WriteLine(1 | 1);//结果为1
                Console.WriteLine(1 | 0);//结果为1
                Console.WriteLine(0 | 0);//结果为0
    
                Console.WriteLine(1 & 0);//结果为0
                Console.WriteLine(1 & 1);//结果为1
                Console.WriteLine(0 & 0);//结果为0
    
                Console.WriteLine(!true);//结果为False
                Console.WriteLine(!false);//结果为True
    
                Console.ReadKey();
            }
        }
    View Code
    •  结构成员

    public struct 结构名{

      成员(变量 属性 方法)

    下面的代码会报错:使用了未赋值的局部变量

      struct Person
        {
            private string name;
            public string Name
            {
                get { return Name; }
                set { name = value; }
            }
            public void SayHello()
            {
                Console.WriteLine("我叫{0}", this.name);
            }
        }
      class Program
        {
            static void Main(string[] args)
            {
                Person p;
                 p.Name="翟群";
                 p.SayHello();
                Console.ReadKey();
            }
        }
    View Code

    修正:

     struct Person
        {
           public  string name;
           /* public string Name
            {
                get { return Name; }
                set { name = value; }
            }*/
            public void SayHello()
            {
                Console.WriteLine("我叫{0}", this.name);
            }
        }
     class Program
        {
            static void Main(string[] args)
            {
                Person p;
                 p.name="翟群";
                 p.SayHello();
                Console.ReadKey();
            }
        }
    View Code

    使用规则
    1.直接声明变量即可,可以new,也可以不用new

    2.如果结构中使用了属性,则还是需要new

    注意事项

    1.结构本身就是一堆变量,所以定义结构就是为了方便使用变量而已

    2.结构的成员:方法,字段不能赋初值

    public string name="";  

    public static string name="";这样就允许赋初值

    而在类中 是可以对字段赋初值的,开打反编译工作 我们发现,.Net平台会优化我们的代码,将字段放在类的构造函数中赋的初始值。

    3.结构的构造方法,可以重载,但是必须为所有字段赋值,不允许有无参数的构造方法

     struct Mystruct
        {
            public int num1;
            public int num2;
            public Mystruct()//报错
            {
    
            }
        }
    View Code

     结构的本质(本质)

    ->声明一个结构变量,就相当于在内存中声明了结构中定义的变量一样

        struct Mystruct
        {
            public int num1;
            public int num2; 
        }
     class Program
        {
            static void Main(string[] args)
            {
                Mystruct m1;
                Mystruct m2;
                 Mystruct m3;
            }
        }
    View Code

    通过计算 每个地址之间相差为8个字节,说明m1,m2,m3分别占8个字节,即num1的内存空间+num2空间

    ->关于构造方法就是初始化字段

    下面代码有错误

                Mystruct m1;
                Mystruct m2;
                Mystruct m3;
                m1.num1 = 10;
                m1.num2 = 20;
                Console.WriteLine(m1.num1+","+m1.num2);
                Console.WriteLine(m2.num1+","+m2.num2);//报错,使用了未赋值的字段
             Console.ReadKey();
    View Code

    使用New Mystruct()构造方法后就不会报错了。默认的构造方法会给定变量默认的值 数字默认值为0,字符为,bool为false,枚举为0,结构为0,引用为0x0000,表示地址为null.

                Mystruct m1;
                Mystruct m2=new Mystruct();
                Mystruct m3;
                m1.num1 = 10;
                m1.num2 = 20;
                Console.WriteLine(m1.num1+","+m1.num2);
                Console.WriteLine(m2.num1+","+m2.num2);//结果为0,0
                Console.ReadKey();
    View Code

    •  常用的数据结构

    -》堆  仓库  随意放随意取  程序执行时才分配内存,通过调用 new 类名()来初始化(在 C#中)

    -》栈  放奥利奥的杯子 先进去后出 last in  first out的数组内存。 程序编译的时候就分布内存,所以在使用前必须初始化,即在声明时就初始化。比如定义一个 int a 需要立即赋值才能使用,结构可以在new 结构名()的构造方法内部,有系统设定的默认初始值,如上所述(在c#中)

    -》列 排队买饭 先进先出

    • 内存扯淡

     c#是安全性语言。没有赋初值就使用,则报错。

    c语言是可以使用未赋初值的变量。

    调用GC.Collect()后,所有对象都重新分配内存地址,是为了提高性能,将所有对象的内存地址连续排布,方便计算机自己查找内存地址,提高性能。所以回收并不是意味着将计算计内存清零,这样会很消耗时间。我们可以用c语言来演示:

    #include<studio.h>

    int main(int args,char** argv){

      int  *pInt;

      print("%d %d",pInt,*pInt);//运行结果为:4199290 -1545845365 (第一个为地址,第二个为数字)

      return 0;

    以上说明,我们的内存是一直有数据存在着的。我们的c#是安全性语言,它不允许反问计算计算机底层的旧数据。

    c#中GC.collect()重新分布内存的时候是将所有对象复制一份,重新排布内存地址,所以所有对象的内存地址都发生了改变,我们若是用旧地址去访问内存还还是可以得到原来的那个对象。

  • 相关阅读:
    UIView动画设置
    窗口与视图的基本概念
    OC基本框架之-字典类型
    将博客搬至CSDN
    objective-c中的深、浅拷贝
    基础算法之二分法查找
    C语言中格式字符指定输出项的数据类型和输出格式总结
    JavaScript学习笔记(9)——JavaScript语法之流程控制
    JavaScript学习笔记(8)——JavaScript语法之运算符
    JavaScript学习笔记(7)——JavaScript语法之函数
  • 原文地址:https://www.cnblogs.com/tobecabbage/p/3524481.html
Copyright © 2020-2023  润新知