分类: C#

  • 2021.1.16 虚度 游戏 学习

    半天时间王者游戏,接近于晚上有关于C#二维数组的实际练习,首次尝试便出现数组越位的index报错,原因为没有仔细检查嵌套for中的int j=0时后面的i<应改为j<,另外sz.length相当于易语言中取数组成员数(),sz.getlength则为某一维数组的成员数/长度。

    王者游戏铂金钻石单排中勉强能连续胜利,主在于掌握之前的冷静判断与控制,以及不被队友的行为干扰导致冒进和挑衅等判断,但凌晨后精神较困开始容易冒进失去判断和场自控。

    网上买的乐山发货梅菜扣肉还挺像回事,但就是实际量比较少,主要很贵。

    晚上左耳较疼,可能为中耳炎,原因可能因为掏了下早上有点痒的耳朵。

  • C# 二维数组基础

    二维数组中的一行是一个一维数组

    第一纬代表行,第二纬代表列(通常)

    学习技巧:实验从小的开始,熟悉以后开始做

     

    二维数组的初始化构造:

    int a = new int[5];//一维5成员数组

    int[,] b = new int[5,3]

    {

    {1,2,3},

    {4,5,6},

    {7,8,9},

    {10,11,12},

    {13,14,15}

    };

    //5行3列二维数组初始化完毕,结构比较类似json

     

    输出二维数组(示例):

    for(int row = 0;row < b.length(0);row++) //这里(0)代表二维数组的行,即5

    {

    for(int col = 0;col < b.length(1);col++)

    {

    console.writeline(“{0}\t”,b[row,col]);//输出低几行几列的数组值,并tab分隔

    }

    }

     

    变量常用名表示法:

    row 行

    col 列

     

    属性与方法的概念:

    如一个人信息:

    身份证号码>属性

    会做饭、写代码>方法

  • 2021.1.4 C#函数和方法基础笔记+经验

    函数和方法区别

    项目文件:ConsolStudy

    C#中方法和函数几乎没有实际区别,简单说只是说法不同,class类中包含多个方法,也叫成员函数,在调用非static静态方法/函数时,需要动态创建函数,同理易语言。若有static则在代码运行时该函数就已经内存中占用创建。

    百度百科:

    https://baike.baidu.com/item/%E6%96%B9%E6%B3%95/3009367?fr=aladdin

     

    网络说明:

    其实是一个意思。从语意上来说,函数是function,多指以前面向过程编程时候,将逻辑编写为一个一个过程,称之为函数。后来发展为面向对象,代码以类的方式来组织,类的里面是成员变量和成员函数,也叫做数据和方法(method).不同时期,有不同的习惯叫法,但是事实是一回事。

    菜鸟教程代码示范:

    https://www.runoob.com/csharp/csharp-methods.html

     

     

    静态调用:

    C#代码批量注释

    https://blog.csdn.net/acetaohai123123/article/details/78266979

    选中一批文本之后

    批量增加注释:Ctrl+K Ctrl+C

    批量取消注释:Ctrl+K Ctrl+U

    实际:选中代码,Ctrl按住不放,先后顺序K和C,解除顺序是先K后U。

     

    C#中char不论中英文只能一个字符

    C#中char的字符概念不分易语言中文2字节和字母1字节占用之分,char=1字母||char=1汉字

    实测:

    与易语言中文占两个字符/字节不同,C#中好像已经规范了中文为一个字符,易语言中这里中文stra会为4:

     

  • 2020.12.4 C#数组基础笔记

    数组定义

    类型[] 数组名;//元素类型[秩] 变量名称

    顺序:

    int[] a;//1.定义数组(并没有创建出来)

    a = new int[5];//2.分配数组空间 注:这里[5]是定义数量,5个空间

    //3.访问(读-写)数组元素

    Console.writeline(a[0]);//这里[0]是内存数组实际下标

    Console.writeline(a[1]);

    数组下标越位、不存在的位输出:

     

    数组定义-其他类型

    bool[] a;

    string[] a;

     

    数组定义-更简单方式:

    int[5]{1,2,3,4,5};

    或

    long[] = {0,1,2,3};

     

    后定义

    int[] a;

    a = new int[5];//后定义

     

    取数组长度/数量

    Console.writeline(a.length);//如:a[5]取出5

     

    数组直接赋值

    a[0] = 1;//直接赋值(这里整数int型)

    a[1] = 2;

    访问任意长度的数组(基础常用重点)

    for(int i = 0;i < a.length;i++)//循环数组任意长度/数量

    {

    Console.write(a[i]);//循环输出

    }

     

  • 2020.12.4 C#数组与内存关系笔记

    首地址

    数组变量实际上存储的是数组的在内存中的首元素的地址(首地址),而非整个数组的内容

    即:

    int[5] long;

    long为数组变量的首地址,赋值例程见下

     

    数组变量与内存之间的关系

    a= 【1001】 内存地址 详见图

    32位系统,内存4字节整数标识

    63位系统则8字节地址

     

    取字符中的字符

    Char.isLetter(s[i]);//判断字符是否为字母,返回bool逻辑型

    Char.isDigit(s[i]);//判断字符是否是一个数字

  • 2020.12.2 C#基础笔记B

    return

    退出一个(当前)方法

     

    取偶数和取奇数

    if(i%2 == 0)//取偶数

    if(i%2 != 0)//取奇数

    注:0为取余整数的意思

     

    continue;

    结束本次循环,但不跳出,继续下次下循环(如for循环中i++会执行,因为结束后面循环体代码但i++循环后事件依旧执行)

     

    控制台输入

    Console.Readline();

     

    设置控制台窗口大小

    Console.setWindowsSize(w,h);//宽,高,整数参数,单位约一个字符行列

     

    设置控制台光标位置

    Console.setWindowsPosition(w,h);//宽,高,光标定位,决定一次输入输出的位置

     

    控制台清屏

    Console.clear();

     

    九九乘法表例程

     

     

     

  • 2020.12.2 C#基础笔记A

    #region代码块注释 折叠展开用

    #region

    {

    }

    #endregion

     

    Alt键技巧 多行操作

    多行代码快速操作,如 按住Alt后选择多行代码delete删除或删除部分:

    console.writeline(“a”);

    console.writeline(“b”);

    多汗选中line,按下delete后:

    console.write(“a”);

    console.write(“b”);

     

    分号与for特殊用法,什么都不做,结束函数

    如:

    for(int i = 1,i < 10000,i++);//此用法可让for实现暂停延时,无需花括号

    注:循环体如果只有一条语句,可以不套花括号

     

    for(;;)//条件可为空,实现死循环

    {

    }

     

    \t 一个制表位

    空一个制表位,8个空格,类似tab

     

    \n 换行字符

    控制字符/特殊不可见字符

     

    输出指定位置字符

    注:char 字符串中的一个字符

    String s = “测试”;

    Console.write(s[0]);

    输出“测”第一个字符

    注:双引号为字符串,一个单引号(‘’即char型)只能指定一个字符,不管中英文字母只能一个

     

    break和其他特殊用法

    if(i == 5)//这里无花括号

    break;//直接跳出当前循环体

     

    取数据长度

    x.lenth();

    取出返回长度整数

     

    int数据转换

    int cun = int.Parse(Console.Readline());//输入存款金额

     

  • 2020.11.21 C#基础笔记

    https://www.bilibili.com/video/BV1w4411D78z?p=15

     

    定义变量:

    {

    int hp;

    }

    int 数据格式/数据类型。

    hp 变量名。

     

    float 浮点型/小数:

    {

    float pi;

    pi = 3.14f;//加f标识浮点数常量,小数加f,无小数可不加,否则程序可能识别为double类型

    }

     

    连续定义多个变量:

    {

    string oldName,newName;//连续赋值变量、驼峰命名方式

    }

     

    随机数:

    {

    Random rnd = new Random();

    rnd.Next(3);//产生小于3的随机数

    }

     

    数据类型转换到int型:

    {

    string shp;

    //<<= int.parse(shp);

    }

    shp为有效类型,如整数字符串,将字符变量shp转换到整数型

     

    for循环解析:

    for(int i = 1;i <= 10;i++)

    {

    }

    int i = 1 定义及初始值,初始循环执行一次

    i <= 10 循环条件,执行11次,第11次不满足该条件跳出

    i++ 循环后做的事情,执行10次

     

    C#特性:花括号内外不能用同名变量

    如:

    {

    int i;

    for(int i;i<=10;i++) { }//此时i会提示存在同名

    }

     

    可直接使用花括号隔离,无需任何定义:

    {

    int i;

    {//单独括号

    for(int i;i<=10;i++) { }//此时i会提示存在同名

    }//单独括号

    }

     

  • C# Await(转载)

    https://www.cnblogs.com/haibozhu/p/11407647.html

    2020.11.18 用于延迟时钟等方面的,存在异步调用注意事项,待继续学习了解

     

    每次提到异步我都选择绕开,感觉深不可测,最近打算看看异步,但又不愿意看书,网上找了几个视频看,发现传智播客的老师讲异步都不是很深入,关键的问题一笔带过,倒是把我弄糊涂了,印象最深刻的是那个老师说的一句话:“在异步函数中,Await之后会自动创建出一个线程”。确实,在控制台程序中是这样,但是在winform中却不都在UI线程中执行,感觉内部隐藏不可告人的秘密,索性自己探索一下。

    控制台程序:

    复制代码
            static void Main(string[] args)
            {
                Console.WriteLine("1.同步ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                RunTimeAsync();
                Console.WriteLine("4.异步执行完毕ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                Console.WriteLine("5.同步延迟完毕ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                Console.ReadKey();
            }
            public async static Task RunTimeAsync()
            {
                Console.WriteLine("2.进入异步ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                await Task.Delay(1000);
                Console.WriteLine("3.异步执行后ThreaID:" + Thread.CurrentThread.ManagedThreadId);
            }
    复制代码

    执行结果:

    同样的代码在winform中执行:

    winform程序:

    复制代码
            private void button1_Click(object sender, EventArgs e)
            {
                Console.WriteLine("1.同步ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                RunTimeAsync();
                Console.WriteLine("4.异步执行完毕ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(2000);
                Console.WriteLine("5.同步延迟完毕ThreaID:" + Thread.CurrentThread.ManagedThreadId);
    
            }
            public async static Task RunTimeAsync()
            {
                Console.WriteLine("2.进入异步ThreaID:" + Thread.CurrentThread.ManagedThreadId);
                await Task.Delay(1000);
                Console.WriteLine("3.异步执行后ThreaID:" + Thread.CurrentThread.ManagedThreadId);
            }
    复制代码

    执行结果:

    前后代码执行结果对比后发现,

    1.线程数量,winfrom都是在一个线程里执行,控制台程序是两个线程执行,其中异步操作在新的线程里。

    2.执行顺序,winform先执行click中同步操作,再执行异步操作,控制台却相反。

    所以await这个关键字到底对异步操作动了什么手脚呢?

    在查了一些相关资料后有两个词比较高频:SynchronizationContext 和TaskScheduler,执行代码时,Task不会自己执行,而是将执行内容放到SynchronizationContext 和TaskScheduler执行。

    其实await Task.Delay(1000)或者await AsyncFun()(异步操作)等价于以下代码:

    Task t = AsyncFun();
    var currentContext = SynchronizationContext.Current;
    if (null  == currentContext)
    {
    t.ContinueWith((te) => { Run(); }, TaskScheduler.Current);
    }
    else
    {
    t.ContinueWith((te) => { Run(); }, TaskScheduler.FromCurrentSynchronizationContext())

    }

    如果SynchronizationContext为null就在TaskScheduler中执行,如果不为null则在FromCurrentSynchronizationContext中执行。

    先了解一下TaskScheduler——–CSDN中注解是:表示一个处理将任务排队到线程中的低级工作的对象。

    看一下TaskScheduler的元数据:

    TaskScheduler其实就是将Task放到Threadpool执行,通过入队出队的方式排列执行顺序。

    根据等价代码我们要区分一下控制台程序与winfrom程序异步操作的执行方式,

    我们执行这条代码:var currentContext = SynchronizationContext.Current;

    在控制台程序中currentContext 为null

    在winform中currentContext 为System.Windows.Forms.WindowsFormsSynchronizationContext

    那么控制台程序是在TaskScheduler.Current所在的线程池执行,我们看到控制台的await 异步操作在其他线程中执行一致。

    下面分析一下winform的执行方式:

    WindowsFormsSynchronizationContext继承自SynchronizationContext,

    https://www.cnblogs.com/lzxianren/p/SynchronizationContext.html   参考了这篇文章

    里面有两点:

    public virtual void Send(SendOrPostCallback d, Object state)

    {

    d(state);

    }

    public virtual void Post(SendOrPostCallback d, Object state)

    {

    ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);

    }

    在UI线程执行是,会将执行的任务用Send方法放到消息泵中,当时UI中同步执行的操作执行完毕,再执行详细泵中的数据,这就是为什么UI中只在一个线程中执行,而且总是在最后执行。

    总结:用 await 语句等待一个任务完成,当该方法在 await 处暂停时,就可以捕捉上下文(context)。如果当前 SynchronizationContext 不为空,这个上下文就是当前SynchronizationContext;如果当前 SynchronizationContext 为空,则这个上下文为当前askScheduler,该方法会在这个上下文中继续运行。一般来说,运行 UI 线程时采用 UI 上下文,处理 ASP.NET 请求时采用 ASP.NET 请求上下文,其他很多情况下则采用线程池上下文。因此,在上面的代码中,每个同步程序块会试图在原始的上下文中恢复运行。如果在 UI线程中调用 ,这个方法的每个同步程序块都将在此 UI 线程上运行。但是,如果在线程池线程中调用,每个同步程序块将在线程池线程上运行。

    控制台程序以及类库是在TaskScheduler中调度执行,UI程序则是在SynchronizationContext调度执行。

    参考了:https://blog.csdn.net/wlk1229/article/details/81287374   

  • C#嵌套类的使用方法及特性(转载)

    https://blog.csdn.net/luqizheng/article/details/1965220

    嵌套类(Nested Class)是在类中定义的类。以下把拥有内嵌类的类称为外部类。根据《深入理解嵌套类和内部类》嵌套类分为静态嵌套类和非静态嵌套类,其中非静态嵌套类页被称为内部类。 嵌套类在UML中是composite的另外一种代码表示形式,表示耦合度更高,并且与外部类更加紧密。

           一般类的 访问修饰符可以定义为默认的internal 或者public,而内嵌类就有比较多的选择,可以是为protected、internal、public以及默认的private。

    内嵌类与外部类的访问限制

          嵌套类可以访问外部类的方法、属性、字段而不管访问修饰符的限制。如:   

    public   class  A
        {
             private   static   int  _AInt;
             private   int  _instanceInt;
             private   static   void  AMethod()
            {
                Console.WriteLine(_AInt);
            }
             public   void  SayIt()
            {
                NestedA.Method( this );
            }
             /* 嵌套类 定义 */ 
             private   class  NestedA
            {
                 public   static   void  Method(A a)
                {
                     // 静态成员 
                    _AInt  =   100 ;
                    AMethod();
                     //实例 成员 
                    a._instanceInt  =   10 ;
                    a.SayIt();
                }
            }
        }

          但是外部类只能够访问修饰符为public、internal嵌套类的字段、方法、属性。示例如下:  public   class  A
        {
             public   static   void  AMethod()
            {
                 // 成功 
                NestedA.StaticMethod();
                 // 编译报错 
                NestedA._Int  =   100 ;

                NestedA ins = new  NestedA();
                 // 成功 
                ins.Method();
                 // 编译报错 
                ins._instanceInt  =   100 ;
            }
             /* 嵌套类 定义 */ 
             private   class  NestedA
            {
                 private   static   int  _Int;
                 private   int  _instanceInt;
                 public   static   void  StaticMethod() { }
                 public   void  Method(){}
            }
        }

        嵌套类访问外部类实例的方法、字段、属性时候。一般在采取构造函数输入外部类。如下:   public   class  A
            {
                 private   int  _a;

                 /* 嵌套类 定义 */ 
                 private   class  NestedA
                {
                     public  NestedA(A a)
                    {
                        a._a  =   9 ;
                    }              
                }
            }

     继承

            继承类,也就是继承类外部类的类,只能使用父类中嵌套类的public或者internal(同一个程序集合)方法。但是继承类可以再定义一个内嵌类并从继承父类中嵌套类。如:public   class  A
    {
                 /* 嵌套类 定义 */ 
                 protected   class  Nested
                {
                     protected   virtual   void  BaseNested_Method(){}
                }
    }

      public   class  C : A
    {
           /* 内嵌类 定义 */ 
           protected   class  C_Nested:Nested
          {
                     protected   override   void  BaseNested_Method()
                    {
                         // 重写部分 
            }
           }
     }

          因为C中A中继承,因此C_Nested可以继承Nested类,从而获取重写父嵌套类的机会。但是Nested必须是可继承类及可访问的(非private 、sealed、static)。

             嵌套类可以随意外部类的任何数据属性,而外部类访问嵌套类就只能遵守访问修饰符。从这个角度看,嵌套类是外部类的补充,通过嵌套类可以获取更好的封装性,增加外部类的可维护性和可读性。       

          从程序结构看,嵌套类在逻辑上更加接近使用类。可以更有效地表示类与类之间的紧密程度。为类管理提供除命名空间外的另一种方法。

    懒加载

            嵌套类的静态构造函数不会随着外部类的触发而初始化。因此可以有效地避免创建时候初始化时间,当需要使用内嵌类的时候,嵌套类才开始初始化才开始初始化。public   class  Outside
    {
         static  Outside()
        {
            Console.WriteLine( ” Outside Inilizlized ” );
        }
         public   void  SayIt()
        {
            Nested.Run();
        }
         private   class  Nested
        {
             static  Nested()
            {
                Console.WriteLine( ” Nested initilized ” );
            }

             public   static   void  Run()
            {
                Console.WriteLine( ” Nested Run ” );
            }
        }
    }

    执行结果 Outside o  =   new  Outside(); // 打印”Outside Inilizlized” 
     Console.ReadLine();
     o.SayIt(); // 首先打印”Nested initilized” 再打印 “Nested Run” 
     Console.ReadLine();

          一般应用这个特性会在一些C#单例模式中找到,而这种模式可以被称为Fully lazy singleton模式。下面是简单的演示代码(Singleton模式可以在这里有更加详细的解释):public   class  Singleton
        {
             public   static  Singleton Instance
            {
                 get 
                {
                     return  Nested.instance;
                }
            }
             private   class  Nested
            {
                 public   readonly   static  Singleton instance = new  Singleton();
            }
    }

     反射

          反射内嵌类需要使用”+”而不是我们常使用的”.” 。如A类在Assembly名称为InsideClass中。namespace  InsideClass
    {
         public   class  A
        {
              public   class  Nested
            {
                 protected   void  BaseNested_Method()
                {
                }
            }
         }
    }

    执行  // 成功 
    object  o1  =  System.Activator.CreateInstance( ” InsideClass ” ,  ” InsideClass.A+Nested ” );
      // 失败 抛出System.TypeLoadException 异常 
    object  o2  =  System.Activator.CreateInstance( ” InsideClass ” ,  ” InsideClass.A.Nested ” );