• C#语法杂谈


    1. 值类型和引用类型

    1.1 值类型

    比如int,float,struct等,和C/C++中的变量差不多,但编译器会强制你必须先初始化再使用,避免一不小心使用了未初始化的变量。

    1.2 引用类型

    class是引用类型,其默认行为类似于引用或指针(?但可以通过重载函数改变其默认行为?)。

    注:尽管教科书上一般将class归为引用类型,但我倾向于将它们看作指针类型,一方面是因为它们的行为更像是指针,另一方面是便于与函数引用参数ref区分开。

    比如你定义了一个class MyClass,现在想要一个MyClass类型的变量,那么必须这样:

    MyClass myClass = new MyClass();

    而不能简单地MyClass myclass完事。

    又如语句MyClass anotherMyClass = myClass,其效果等价于指针赋值。

    1.3 总结

    不管是值类型还是引用类型,编译器都强制必须先初始化后使用,因此在定义和初始化上两者并无明显区别。它们的主要区别在于赋值运算符和函数参数传递时。

    2. 变量初始化

    因为编译器强制变量必须初始化后再使用,因此如下代码是无法通过编译的:

    int i;
    if(condition) {
        i = 1;
    }
    Console.WriteLine(i);

    由于condition的不确定,编译器无法确认i是否得到了初始化。但下面代码可以:

    int i;
    if(true) {
        i = 1;
    }
    Console.WriteLine(i);

    上面的代码中,编译器可以确定i得到了初始化。类似下面的代码也是可以的:

    int i;
    for(;;)
    {
        i = 1;
     break; } Console.WriteLine(i);

     P.S. 因为这个强制初始化要求,所以函数参数必须能够具备out属性用于传递一个未经初始化的变量,以避免不必要的初始化。

    又P.S. 从上面代码中可以看出,圣书《C#入门经典》关于for循环体中变量作用域的解释并不正确,至少第五版是如此。书中那段不能通过编译的代码,主要原因是编译器无法确认for循环是否一定执行(尽管程序员可以确认),也就无法确认变量是否在for循环中得到了初始化,而不是因为书中那段估计作者自己都看不明白的解释(中文版第五版,正文p123-124)。

    3. 数组

    3.1 如上所述,数组也必须初始化后再使用,例如int[] array = new int[3]。但是可以省略数组每个元素的初始化:编译器会将它们初始化为默认值。

    3.2 多维数组

    其含义等价于C语言的多维数组,但语法不同,例如int[,] array = new int[3,4]。

    3.3 数组的数组

    数组的数组可以理解为指针数组,数组的每个元素都是个“指针”,指向另一个数组。所以初始化也分两级。例如:

    int[][] array = new int[][] { new int[3], new int[4] };

    4. 函数参数

    void test(MyClass myClass)
    {
    myClass.dosomething();
    myClass = new MyClass(); }
    void test(ref MyClass myClass) {
    myCLass.dosomething();
    myClass = new MyClass(); }

    如上文所述,class的行为像指针。所以形参myClass上的dosomething()是作用于实参上的。非ref参数的test函数中,myClass=new MyClass()会覆盖形参但不会影响实参;而ref参数的test函数中,myClass=new MyClass()会同时覆盖掉实参。

    5. 委托

    简单情况下,委托的定义类似于class,使用起来类似于函数指针。

    // 1. 定义一个委托“类”
    //     下面这条语句一般位于那些可用来放置class定义的地方
    delegate void MyDelegate();
    // 2. 声明(并在需要时初始化)一个委托“类”的实例
    MyDelegate myDelegate = MyFunction;
    // 3. 使用该“类”的实例:通过委托调用函数
    myDelegate();

    6. virtual、override和new

    如果你想要多态,在基类中使用virtual,在继承类中使用override;

    如果你想要重新实现,在继承类中使用new。

    7. 属性

    举个栗子:很多论坛对长贴提供直接输入分页进行跳转的功能,基于C/C++/C#程序员的骄傲,在代码内部分页总是从0开始计数,但显示值总是从1开始计数:

    class MyClass
    {
        private int _page;
        public int page
        {
            get
            {
                return _page + 1;
           }
            set
            {
                _page = value - 1;
            }
        }
    }

    属性功能上类似于下面代码,但让你可以用访问成员变量的语法去访问属性。

    // C#伪代码
    public int get_page()
    {
        return _page + 1;
    }
    public void set_page(int value)
    {
        // value实际上是C#关键字,
        // 在set方法中使用。
        _page = value - 1;
    }
  • 相关阅读:
    Warning:mailcious javascript detected on this domain来由
    CSS盒模型重新理解篇
    sublime生产力提升利器
    Aptana studio 3前端开发编辑器推荐
    Provides PHP completions for Sublime Text
    关于google电子地图跟卫星地图位置不重合
    无名前端库
    npm 编写cli
    webpack.merge
    ExcelDNA UDF 攻略
  • 原文地址:https://www.cnblogs.com/byeyear/p/5136581.html
Copyright © 2020-2023  润新知