• C#笔记


    1、ref与out关键字

    不同点:

    ref:参数传入方法前,需要先赋值。

    out:参数传入方法前,对赋值没有要求,但是方法内必须对参数赋值。

    (如果没按要求赋值,编辑器会报错)

    相同点:

    ref与out标记参数时,方法内改变参数的值,变量的值也发生变化。

    protected void Page_Load(object sender, EventArgs e)
        {
            string j="初始值";
            refTest(ref j);
            Console.Write(j); //此时j="改变值",out与ref都会改变 变量 的值。
            test(j);
            Console.Write(j); //此时j="改变值",test方法并没有将j的值改变
        }
        static void refTest(ref string a)
        {
            a = "改变值";
        }
    
        static void test(string a)
        {
            a = "改变不了";
        }

     2、委托与事件

    场景:下一个页面(类)去执行上一个页面(类)的方法。(A页面跳转到B页面,在B页面通过事件的方法,触发A页面的方法运行。)

               用于两个类中的某些方法不方便直接调用。

       A页面:

       B  b=new B();

       b.event +=new  B.method(test);      //事件可以添加多个,里面的方法会依次执行 

       b.main();

      private void test()

      {

          //一些操作,例如girdView重新加载数据

      }

       B页面:

       public delegate void method();

       public event method event1;

       public void main()

       {

           if(event1!=null)

            {

                   event1();   //此时会触发A页面页面的test方法。

            }

       }

    A页面:

    public partial class delegate1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Class1 cl = new Class1();
            cl.shijian += new Class1.weituo(test);   //将test方法委托
            cl.test2(); //执行class1的test2方法
    
        }
        private void test()
        {
            string a = "ceshi";
        }
    }

     B页面:

    public class Class1
    {
        public delegate void weituo();
        public event weituo shijian;
        public void test2()
        {
            if (shijian != null)
            {
                shijian();  //此时去执行A页面里面test方法。
            }
        }
    }

     使用规范:

    (1). 委托类型的名称都应该以 EventHandler 结束。

    (2). 委托的原型定义:有一个void 返回值,并接受两个输入参数:一个Object 类型,一个EventArgs 类型(或继承自EventArgs)。

    (3). 事件的命名为委托去掉 EventHandler 之后剩余的部分。

    (4). 继承自 EventArgs 的类型应该以EventArgs 结尾。

    3、泛型

        class A<T> where T : class    //T必须是一个class类型

         {

                 public T  a;

                 public T  method(T t)

                 {

                          return t;

                 }

         }

           where T : struct | T必须是一个结构类型
      where T : class T必须是一个类(class)类型
      where T : new() | T必须要有一个无参构造函数
      where T : NameOfBaseClass | T必须继承名为NameOfBaseClass的类
      where T : NameOfInterface | T必须实现名为NameOfInterface的接口

    4、重写与覆盖

          父类使用virtual关键字修饰的方法(虚方法),子类中可以对父类中的虚方法进行重写(使用override关键字)

          父类中不使用virtual修饰的方法(实方法),子类只能对父类中的实方法进行覆盖(使用new关键字)

          虚方法、实方法都可以被覆盖(new)。

          覆盖与重写的区别:

          重写会改变父类方法的功能,覆盖不会改变父类方法的功能。

          

    public class Class1
        {
            public virtual string test1()    //虚方法
            {
                return "重写前";
            }
            public string test2()            //实方法
            {
                return "覆盖前";
            }
        }
        public class Class2 : Class1
        {
            public override string test1()  //使用关键字重写父类的test1方法
            {
                return "重写后";
            }
            public new string test2()//使用new关键字覆盖父类的test1方法
            {
                return "覆盖后";
            }
        }
        public class Class3
        {
            public void test()
            {
                Class1 a = new Class2();
                string z = a.test1();       //此时Z   重写后    Class2将test1重写了。
                string zz = a.test2();      //此时ZZ  覆盖前    
            }
        }

     5、单例模式

           一、使用类行为创建

           单例模式的类中,需要注意的事项:

         (1)类变量  _singleTon需要被private static修饰,用于获取对象的方法(static类型)以及防止类的外部访问。

         (2)获取类对象的方法 getInstance() 需要被public static修饰,外部通过类名加 . 的方式获取对象。

           总结:类中含有两种东西(对象变量_singleTon,获取对象的方法getInstance),其中第一个是private static,后一个public static。

    /// <summary>
    /// 单例模式
    /// </summary>
    public class SingleTon
    {
        private static SingleTon _singleTon = null;public static SingleTon getInstance()
        {
            if (_singleTon == null)
            {
                _singleTon = new SingleTon();
            }
            return _singleTon;
        }
    }

      此时有一个缺点,多线程情况下(两个线程同时获取类对象,就会创建两个对象)

      优化一下(加上同步锁)

    /// <summary>
    /// 单例模式
    /// </summary>
    public class SingleTon
    {
        private static SingleTon _singleTon = null; 
        private static object SingleTon_lock = new object();  //同步锁
        /// <summary>
        /// 防止类的外部使用new的方式创建该对象
        /// </summary>
    
        public static SingleTon getInstance()
        {
            lock (SingleTon_lock)
            {
                if (_singleTon == null)
                {
                    _singleTon = new SingleTon();
                }
                return _singleTon;
            }
        }
    }

         二、使用静态变量创建

    public class SingletonThird
        {
            /// <summary>
            /// 静态变量
            /// </summary>
            private static SingletonThird _SingletonThird = new SingletonThird();
            
            public static SingletonThird CreateInstance()
            {
                return _SingletonThird;
            }
        }

    是不是觉得很优雅, 利用静态变量去实现单例,  由CLR保证,在程序第一次使用该类之前被调用,而且只调用一次

    PS: 但是他的缺点也很明显, 在程序初始化后, 静态对象就被CLR构造了, 哪怕你没用。

       

    三、使用静态构造函数创建

    public class SingletonSecond
        {
            private static SingletonSecond _SingletonSecond = null;
    
            static SingletonSecond()
            {
                
                _SingletonSecond = new SingletonSecond();
            }
            
            public static SingletonSecond CreateInstance()
            {
                return _SingletonSecond;
            }
        }

    静态构造函数:只能有一个,无参数的,程序无法调用 。

    同样是由CLR保证,在程序第一次使用该类之前被调用,而且只调用一次

    同静态变量一样, 它会随着程序运行, 就被实例化, 同静态变量一个道理。

    6、C#中值类型和引用类型的区别

           (1).    值类型的数据存储在内存的栈中;引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址。

           (2).     值类型存取速度快,引用类型存取速度慢。

           (3).     值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用

           (4).     值类型继承自System.ValueType,引用类型继承自System.Object

           (5).     栈的内存分配是自动释放;而堆在.NET中会有GC来释放       

           (6).      值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的地址,即对象的引用。

           (7). 值类型变量直接把变量的值保存在堆栈中,引用类型的变量把实际数据的地址保存在堆栈中,而实际数据则保存在堆中。注意,堆和堆栈是两个不同的概念,在内存中的存储位置也不相同,堆一般用于存储可变长度的数据,如字符串类型;而堆栈则用于存储固定长度的数据,如整型类型的数据int(每个int变量占用四个字节)。由数据存储的位置可以得知,当把一个值变量赋给另一个值变量时,会在堆栈中保存两个完全相同的值;而把一个引用变量赋给另一个引用变量,则会在堆栈中保存对同一个堆位置的两个引用,即在堆栈保存的是同一个堆的地址。在进行数据操作时,对于值类型,由于每个变量都有自己的值,因此对一个变量的操作不会影响到其它变量;对于引用类型的变量,对一个变量的数据进行操作就是对这个变量在堆中的数据进行操作,如果两个引用类型的变量引用同一个对象,实际含义就是它们在堆栈中保存的堆的地址相同,因此对一个变量的操作就会影响到引用同一个对象的另一个变量。

            int a = 1;
            int b = a;
            a = 3;    //此时b仍然为1
            Class2 cl = new Class2();
            Class2 c2 = cl;
            cl.a = "123456";   //此时引用C2的a也变成了123456

     7、try catch finally 异常

           finally里面的语句,无论程序是否出现异常或者return,都会执行finally里面的语句。

             使用场景(关闭数据库连接,无论是否执行成功,都要关闭了数据库连接)

             使用方法  try与catch(可以有多个,也可以没有,没有时需要加finally,finally只能有一个或者没有)。

    try
    
    {
    
           //执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
    
    } 
    
    catch
    
    {
    
          //除非try里面执行代码发生了异常,否则这里的代码不会执行
    
    } 
    
    finally
    
    {
    
         //不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally  
    
    }

     8、索引器

           索引器由             修饰符  返回类型 加 this[参数类型  参数值](public string this[int index,string b]{   })               构成, 索引器的索引值不受类型限制。

            索引器里面需要有get set访问器。

            调用方式可以是:   

            Class cl=new Class();

            cl[0]="对class对象里面a赋值";

            索引器的作用: 可以使得类的实例能够像数组那样使用一样,又称为带参属性        

          (1)索引器与数组的比较:

                 索引器的索引值不受类型限制。用来访问数组的索引值一定是整数,而索引器可以是其他类型的索引值。
                 索引器允许重载,一个类可以有多个索引器。
                 索引器不是一个变量没有直接对应的数据存储地方。索引器有get和set访问器。
                 索引器允许类和结构的实例按照与数组相同的方式进行索引,索引器类似与属性,不同之处在于他们的访问器采用参数。被称为有参属性。

          (2)索引器与属性的比较:
                标示方式:属性以名称来标识,索引器以函数签名来标识。
                索引器可以被重载。属性则不可以被重载。
                属性可以为静态的,索引器属于实例成员,不能被声明为static

        public string a { get; set; }
        public string b { get; set; }
    
        public string this[int index]
        {
            get
            {
                if (index == 0)
                {
                    return a;
                }
                else
                    return b;
            }
            set
            {
                if (index == 0)
                {
                    a = value;
                }
                else
                    b = value;
            }
        }
  • 相关阅读:
    扒几个 3D 模型备用
    向 3D 世界迈出一小步
    为什么说使用 Linux 系统学习 OpenGL 更方便
    Windows 下的 Linux环境
    windows git 的扩展用法——其他linux命令
    Linux 环境变量
    powershell(或者windows terminal)中使用git
    QT无边框窗体——拦截windows消息实现
    QT工具——开发技巧与其他工具
    QT工具——国际化工具
  • 原文地址:https://www.cnblogs.com/zl181015/p/10690881.html
Copyright © 2020-2023  润新知