C#基础及配置

一、C#的基础配置及运行环境

  • 学习环境:Win10
  • C#在Win10中的运行:使用命令行csc test.cs(test为C#文件名)
    使用命令行运行的前期配置:


    C#基础及配置_第1张图片

    找到V4.0.30319
    然后将该路径C:\Windows\Microsoft.NET\Framework64\v4.0.30319添加到系统的环境变量中:


    C#基础及配置_第2张图片
    环境变量的配置

    后续即可在.cs文件的文件夹中使用命令行csc test.cs运行该程序

二、C#的基本结构

一个简单的HelloWorld程序

using System;
namespace HelloWorldAppication
{
    class HelloWorld
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
            Console.ReadKey();
        }
    }
}

主要包括命名空间声明,一个class,class方法,class属性,一个Main方法,预计及表达式。
程序的第一行,using System表示向程序中加入所需的System命名空间,一个程序一般有多个using语句。
第二行是对namespace的声明,一个namespace中包含一系列的类。在该HelloWorld程序中表示命名空间HelloWorldApplication中包含HelloWorld类。
第四行是对class的声明,类一般包含多个方法,方法定义了类的行为。在该HelloWorld程序中,HelloWorld类只有一个Main方法。
第六行是Main方法的定义,所有C#的程序入口,所有程序的执行都从Main开始。
第八行中通过调用System命名空间中的Console类中的方法WriteLine进行屏幕的输出。
第九行Console.ReadKey()指的是等待一个键的输入,防止在执行exe文件时屏幕快速运行并关闭。


根据HelloWorld程序以及一些额外的程序可以总结一下C#的基本语法结构。
1、任何C#程序的第一行语句都是using System;一个程序可以允许有多个using语句,根据程序中的语句需要进行添加。
2、namespace是对命名空间的声明,里面可以包含多个类,类与类之间可以存在继承等关系。具体程序执行的入口为存在Main方法的类下。
3、类中存在成员变量及方法,成员变量在方法前进行定义以存储数据或表示属性,在方法内可直接使用,并影响最终的数据值。方法,成员函数在类内声明,可以执行特定的任务。
4、在Main()方法中,可以对其他的类进行实例化使用。


三、数据类型

C#中,变量分为3中类型:值,引用,指针
值类型
值类型直接包含数据,如:int存储数字,char存储字符,float存储浮点数。
如需得到一个类型或一个变量在特定平台的准确尺寸,可以用sizeof(type)


引用类型
引用类型包含对变量的引用,指的是一个内存的位置。如果内存位置的数据发生改变,其他变量会自动反映出值的变化。
内置的引用类型有:object,dynamic,string

  • 对象类型object
    对象类型可以被分配其他任何类型的值,但是分配前需要进行类型的转换。
    一个值类型转换为对象类型时,称为“装箱”;反之,称为“拆箱”。只有装过箱的数据才能进行拆箱。
    装箱只是复制了数值对其进行操作,不会对原来的数值有所影响。
int val = 2019;
object obj;     //定义一个对象类型
obj = val;      //装箱
int nval = (int) obj;       //拆箱
  • 动态类型dynamic
    动态类型与对象类型相似,可以存储任何类型的值,但是对象类型的检查在编译时发生,而动态类型在运行时发生。
  • 字符串类型string
    字符串类型允许分配任何字符串值。
    字符串定义的时候引号前面加@可以将转义字符(\)当做普通字符来看待。

指针类型
指针类型用于存储另一类型的内存地址。


注意:
每个值类型都有一个独立的内存区保存自己的值,调用的时候调用的是他的值。而引用类型调用的是他的地址,两个会共用同一个内存空间,内存中的值改变时,调用的和被调用的值都会发生改变,下面将详细说明。
值类型在声明的时候,是在栈中开辟一个内存空间来存放相应的值,值类型发生改变时,直接修改该内存空间保存的值。

using System;
namespace TestApplication
{
    class Test
    {
        //主函数
        static void Main(string[] args)
        {
            int n1 = 2019;
            int n2 = n1;
            Console.WriteLine(n1 + " " + n2);
            n1 = 2020;
            Console.WriteLine(n1 + " " + n2);
            Console.ReadKey();
        }
    }
}

代码输出结果:
2019 2019
2020 2019

先在栈中开辟一个空间存储n1的值2019,后在栈中开辟另一个空间存储n2的值2019,当n1的值发生了改变时,将n1在栈中对应空间中存储的值改为2020,而对n2栈中对应空间中存储的值不会发生改变。
引用类型在声明的时候,先在堆中开辟一个内存空间来存放对应的值,再在栈中开辟一个内存空间来存在堆中开辟空间的内存地址。当调用引用类型时,先从栈中获取地址,再根据地址到堆中找到对应的空间获取数值。

using System;
namespace TestApplication
{
    class Test
    {
        //主函数
        static void Main(string[] args)
        {
            string[] s1 = new string[]{"a", "b", "c"};
            string[] s2 = s1;
            for(int i = 0; i < s2.Length; i++)
                Console.Write(s2[i]);
            s1[2] = "p";
            Console.WriteLine();
            for(int i = 0; i < s2.Length; i++)
                Console.Write(s2[i]);
            Console.ReadKey();
        }
    }
}

代码输出结果:
abc
abp

先在堆中开辟一个内存空间(假设0X80)存放s1的值,再在栈中开辟一个内存空间存放地址0X80。当s1赋给s2时,在栈中开辟一个新的内存空间保存地址0X80。所以,当s1中的值发生改变时,修改的是地址0X80中存放的值,而s2还是从0X80的堆地址中获取,因此得到的是改变后的值。
字符类型是一种特殊的引用类型

using System;
namespace TestApplication
{
    class Test
    {
        //主函数
        static void Main(string[] args)
        {
            string s1 = "abc";
            string s2 = s1;
            Console.WriteLine(s1 + " " + s2);
            s2 = "def";
            Console.WriteLine(s1 + " " + s2);
            Console.ReadKey();
        }
    }
}

代码输出结果:
abc abc
abc def

先在堆中开辟一个内存空间(假设0X80)存放s1的值,再在栈中开辟一个内存空间存放地址0X80。但是,当s1赋给s2时,首先在堆中开辟一个新的空间(假设0X125)存放值"abc",再在栈中开辟一个新的内存空间保存0X125。当修改了s2的值时,并不是直接修改堆中地址0X125中保存的值,而是再重新开辟一个内存空间(假设0X55)存放"def",然后再在栈中对应的空间将0X125修改为0X55,而堆中0X125中的内存空间将在下次垃圾回收中回收利用。


四、类型转换

类型转换分为隐式类型转换和显式类型转换。

  • 隐式类型转换:不会导致数据丢失,例如从小整型转化为大整型,从派生类转化为基类。
  • 显式类型转换:需要强制转换运算符,会造成数据丢失。
using System;
namespace TestApplication
{
    class Class1
    {

    }

    class Class2 : Class1   //类Class2是类Class1的子类
    {

    }

    class Test
    {
        //主函数
        static void Main(string[] args)
        {
            //隐式转换,将int转换为long
            int n1 = 100;
            long n2 = n1;
            //隐式转换,将一个新建的Class2实例转换为其基类Class1实例
            Class1 c1 = new Class2();
            //强制转换double为int,强制转换不存在四舍五入
            double d = 473.99;
            int i;
            i = (int)d;
            Console.WriteLine(i);
            Console.ReadKey();
        }
    }
}

代码输出结果:
473


详细类型转换:
不同的值类型转换为字符串类型:ToString()
字符串类型(本身整型形式的字符串,若不是,int.Parse()会报错)转换为整型:
1、使用Convert.ToInt32()
2、使用int.Parse()
3、使用int.TryParse(string s, out int i)

  • 当他们对null值进行处理时,Convert.ToInt32(null)会返回0不会产生异常,int.Parse(null)会产生异常。使用int.TryParse(string s, out int i)处理的时候不会抛出异常,成功出相应的值,失败出0。将一个object对象转换为int,Convert.ToInt32()可以,而int.Parse()不行。
  • double类型转为int的时候,Convert.ToInt32()可以四舍六入,出现.5的时候取两边数字中的偶数,如3.5取4,4.5取4。而强制转换时是直接舍去后面的小数位。
using System;
namespace TestApplication
{
    class Test
    {
        //主函数
        static void Main(string[] args)
        {
            //值类型转字符串
            int i = 2019;
            float f = 77.077f;
            double d = 232.32;
            bool b = true;
            Console.WriteLine(i.ToString());
            Console.WriteLine(f.ToString());
            Console.WriteLine(d.ToString());
            Console.WriteLine(b.ToString());
            //字符串转整型
            string s1 = "33";
            int i1 = Convert.ToInt32(s1);
            int i2 = int.Parse(s1);
            Console.WriteLine(i1);
            Console.WriteLine(i2);
            //double转整型
            double d1 = 3.5;
            double d2 = 4.5;
            int i3 = Convert.ToInt32(d1);
            int i4 = Convert.ToInt32(d2);
            Console.WriteLine(i3);
            Console.WriteLine(i4);
            Console.ReadKey();
        }
    }
}

代码输出结果:
2019
77.077
232.32
True
33
33
4
4

你可能感兴趣的:(C#基础及配置)