js选手从0学习C#基础

197 阅读8分钟

安装及第一个helloWorld

  1. 安装Net框架下载 .NET Framework | 免费官方下载 (microsoft.com)

  2. vscode安装C#拓展(可选)

  3. 新建helloWorld.cs文件

    using System;
    ​
    namespace HelloApp{
        class hello{
            static void Main(string[] args){
                Console.WriteLine("Hello world");
                Console.ReadLine();
            }
        }
    }
    

    注意tips:

    • 每个表达式和语句后面都必须要有分号;
    • 文件名可以不和类名一致
  4. cmd中输入 csc helloWorld.cs ,目录下会出现helloWorld.exe运行即可看到cmd中显示‘ hello world'

在vscode中配置C#安装环境

  1. 安装Net框架下载 .NET Framework | 免费官方下载 (microsoft.com)

  2. 扩展搜索并安装 C# 、C# Dev Kit

  3. cmd输入dotnet new console dotnet build dotnet run 直到文件下方出现bin文件夹

    • 之后每次修改文件后都要运行dotnet build,将修改的内容同步到dll文件中去 / 也可以直接用dotnet run调试 /或者修改后在解决方案资源管理器中重新生成
    • 原因:js和c#不同,前者是可以直接在浏览器中运行的语言,后者是需要dotnet编译的语言,也可以理解为类似react/vue框架需要通过webpack编译成浏览器知道的语言才能运行
  4. 将Program文件的内容修改为上述所提到的helloWorld.cs

  5. 右侧debug按钮点击创建launch.json文件,可以看到出现.vscode文件夹里面有一个launch.json文件,为configurations中添加

    {
      
        "version": "0.2.0",
        "configurations": [
            {   "name":"C#net Launch",
                "type": "coreclr",
                "request": "launch",
                "program": "${workspaceFolder}/bin/Debug/net8.0/csharp.dll", //这里文件名可能不一致,根据你的文件名选择后缀为.dll的文件即可
            }
        ]
    }
    

    随后只需按F5即可进行调式C#程序并在下方控制台看到输入的结果

    1. ctrl+shift+P选择打开NET:打开解决方案,在vscode文件栏下方可以看到出现了一个解决方案资源管理器,点击+即可进行添加class等操作

C#基本概念

using System;//必备,包含namespace之前
namespace xxxx{} //包含多个class的空间(主class、实例化class)
class xxx{} //类,包含属性、方法、Main函数
static void Main
double//各类标识符、关键字

tip: 关键字不能用作标识符,如果使用关键字作为标识符,可以在关键字前面加上 @ 字符作为前缀

数据类型

c#数据类型主要有:value\reference\pointer

  • value

    • byte int -> float \ double \ decimal (浮点数从左到右逐渐精确,decimal需要额外存储空间)
    • char' '(string为reference
    • bool
    • struct
  • reference: class、object dynamic 和 string-》类同于js对象[栈中指针指向堆])

  • pointer:

    char* cptr;
    int* iptr;
    

可空类型

可空类型(nullable):?用于对int\double\bool等无法直接赋值为null的数据类型进行null赋值

int? a=3;  //变量a=3|null

?? 用于表示一个变量在为null的时候返回指定的值

int? a=null;
int b;
b=a ?? 5;  //等同于b= (a==null)? 5 :null;

var声明的变量

在C#中用var声明的变量不需要指定数据类型,声明时必须初始化,且一旦声明后无法更改(与js中的var并不相同,倒是有点像js中的const)

var myName="liming";

常见操作value的方法

String
​
        static void Main(string[] args){
            stirng phrase="haha";
            Console.WriteLine(phrase.Length); //获取string长度
            Console.WriteLine(phrase[0]); //获取string下标对应的char
            Console.WriteLine(phrase.IndexOf('a')); //获取char对应的index,这里是1,若找不到则返回-1
            Console.WriteLine(phrase.Contains(h)); //字符串是否包含该char,return boolean
            Console.WriteLine(phrase.Substring(0,2)); //截取字符串,左闭右开,这里是ha
            Console.WriteLine(phrase.ToUpper()) //转化大小写ToLower()
​
            Console.WriteLine("ch\nhaha"); //换行符
            Console.WriteLine("Hello"World");//转义符
            string value = "abc123";
char[] valueArray = value.ToCharArray();//string拆分为char,类似Join(),Split()
            //连接字符串
            Console.WriteLine($"hi {phrase}")
            Console.WriteLine("hi"+phrase)
            Console.ReadLine();
        }
​
Number
 static void Main(string[] args){
            //1.可以直接使用数学运算、遵循运算规律
                //int vs decimal ->decimal eg.5/2.0->2.5
                //int vs int -> int eg.5/2 ->2  向下取整
            int num=5;
            num++;
            num--;
           
​
            //2.use Math.method()
           Console.WriteLine(Math.Abs(num)); //other method like Math.Pow()\Math.max()...
           Console.ReadLine();
        }

数据类型的转换

强制转换

ReadLine()获取的为字符串

假设我们希望获取用户输入的两个数字,并返回他们相加的结果,实现这个程序的思路可能是分别用两个变量存储ReadLine()并相加,但由于ReadLine()获取到的变量默认是字符串,所有我们需要使用Convert方法,将变量转换为int或decimal:

//基本使用
int example=Convert.ToInt32("22") //22//案例中使用
Console.Write("请输入第一个数字:");
double num1=Convert.ToDouble(Console.ReadLine());
Console.Write("请输入第二个数字:");
double num2=Convert.ToDouble(Console.ReadLine());
Console.WriteLine(num1+num2);
Console.ReadLine();

除了Convert,也可以使用另一种方式强制转换:

int num1=5;
int num2=2;
​
int val=num1/num2;  //2
double res=(double)num1/(double)num2;   //2.5
  • 强制转换与Convert()区别

    强制转换直接截断浮点数,Convert()会进行四舍五入

    decimal num=1.5;
    int res=(int)num;  //1
    int result=Convert.ToInt(num);  //2
    

还可以使用Pause() 、TryPause()方法:

  • 将字符串转换为数字数据类型时,请使用 TryParse()
  • 如果转换成功,TryParse() 会返回 true;如果失败,则会返回 false
  • out 参数提供了返回值的方法的辅助手段。 在这种情况下,out 参数返回转换后的值
string first = "5";
string second = "7";
int sum = int.Parse(first) + int.Parse(second);
Console.WriteLine(sum);//12string myInput="2.33455";
decimal.TryParse(myInput,out myInputDecimal);//myInputDecimal=2.33455
隐式转换

赋值给另外一个数or字符串+

byte b = 10;
int i = b; // 隐式转换,不需要显式转换
  • 隐式转换只能将较小范围的数据类型转换为较大范围的数据类型,不能将较大范围的数据类型转换为较小范围的数据类型

数组

创建数组及修改数组的方法:

//创建数组
            //直接给定
        int[] nums={9,7,5,3,1};
            //设定长度为3的字符串数组
        string[] names=new string[3];
//重新赋值修改数组某一项
        names[0]="linda";

创建及修改二维数组方法:

//创建二维数组[,] -> 直接给定
int[,] array={
            {1,2},
            {3,4},
            {5,6}
        }
//设定每一个元素有两个子元素,共有3个这样的元素
 int[,] otherArray=new int[2,3]; //类似array 
        Console.WriteLine(array[0,1]) //2

foreach遍历数组:

foreach(int n in nums){
    int sum+=n;
}

枚举Enum

枚举一系列数值,value类型,具体用法:

enum Day{Sun,Mon,Tue,Wed,Thu,Fri,Sat};
static void Main(){
    int x=(int)Day.Sun;
    int y=(int)Day.Tue;
    Console.WriteLine("Sun={0}",x); //Sun=0
    Console.WriteLine("Tue={0}",y); //Tue=3                            
}

结构体Struct

使用方式:

struct Songs{
    public string songName;
    public string author;
    public int songId;
}
//in a class
Songs lover;
lover.title="lover";
lover.author="Taylor Swift";
lover.songId=1;

struct与class区别

  1. struct值类型,变量在赋值时会复制整个结构,每个变量都有自己的独立副本;class引用类型,两个变量指向同一个对象
  2. struct不能继承、多态,不能有无参数的构造函数;class支持继承多态,可以有无参数的构造函数
  3. struct不能直接设置为null(可以设置为可空类型):class实例默认可以为null

类、构造函数

我们在vscode中可以使用解决方案管理器来新建一个class,这里为Student,并为其添加属性、方法和构造函数

namespace cDemo;
​
public class Student
{
    public string sName; //属性
    public int sNumber;  //属性
    public void sayName(){  //方法
        Console.WriteLine("my name is "+sName);
    }
​
    public Student(string name,int number ){//构造函数
        sName=name;
        sNumber=number;   
    }

}

在主class中就可以直接new Student类,也就是调用Student类中的构造函数,并使用其中的属性和方法:

namespace cDemo
{
    class Program{
        static void Main(string[] args){
​
            Student liming=new ("liming",2020501); //构造函数
            liming.sayName(); //my name is liming
            Console.ReadLine();
        }
    }
}

public/private

get\set

上面演示的都是访问public修饰符属性的方法,如果我们想设置或访问private属性,需要用一个public属性并为他设置get和set方法,如下:

public class Student
{
    public string sName;
    public int sNumber;
    private char sGpa;  //sGpa是private属性
    public char sRating  //使用是sRating代替
    {
        get  //外部调用Student.sRating得到Student.sGpa
        {
            return sGpa;
        }
        set  //外部设置Student.sRating='A'
        {
            HashSet<char> grades = new HashSet<char> { 'A', 'B', 'C', 'D', 'E', 'F' };
            if (grades.Contains(value))
            {
                sGpa = value;
            }
            else
            {
                sGpa = 'N';
            }
        }
    }
​
}
​

如外部调用,如下:

 Student liming = new("liming", 2020501);
​
 liming.sRating = 'R';
Console.WriteLine(liming.sRating); //'N'
​
 liming.sRating='C';
Console.WriteLine(liming.sRating); //'C'
​
​
其他修饰符
  • public:所有对象都可以访问;
  • internal:同一个namespace的对象可以访问;
  • protected:只有该类对象及其子类对象可以访问
  • protected internal:internal+protected
  • private:对象本身在对象内部可以访问;

static

属性

在class内部具有static修饰符的属性只属于class本身而不属于实例,同样是Student:

调用class本身的属性可行,调用实例中的属性不可行,要想通过实例调用static属性,可以为其添加一个方法

//Student.cs
public class Student
{   public static string  school="BJU";
    public static int sCount=0;
}
//Program.cs
  Student liming = new("liming", 2020501);
  Student lihua=new("lihua",2020911);
            Console.WriteLine("共有"+Student.sCount+"名学生"); //共有2名学生
            Console.WriteLine("学生们都来自"+liming.school); //报错!//访问static属性……
public class Student
{   public static string  school="BJU";
    public static int sCount=0;
     public int getStudentCount(){  //为他添加一个方法
        return sCount;
    }
}
​
//Program.cs
  Student liming = new("liming", 2020501);
  Student lihua=new("lihua",2020911);
            Console.WriteLine("学生们都来自"+liming.getStudentCount()); //学生们都来自BJU
方法/class

我们也可以为方法和class添加static修饰符,一般使用这种形式来当作工作函数使用:

//UsefulTool.cs
public static class UsefulTool{
    public static void test(string word){
        Console.WriteLine(word);
    }
}
​
//Program.cs
    //调用:
UsefulTool.test("hi");
//类似诸如此类的工具函数:
Math.Max(2,6);

继承

我们可以通过继承一个类的属性和方法,并在此基础上进行拓展重写

假设我们希望SuperStudent继承Student类,我们可以:

public class SuperStudent:Student{
    //在这里补充新的属性和方法
​
}

如果需要重写一个方法:

  1. 在继承的母类方法上添加virtual

        public virtual void sayName()
        {
            Console.WriteLine("my name is " + sName);
        }
    
  2. 在子类方法上添加override

     public override void sayName()
        {
            Console.WriteLine("i am super student,my name is " + sName);
        }
    

接口Interface

和类的用法一致

C#方法

C#的Method类似其他编程语言中的Function,在C#中只有Main方法中的代码会被执行,我们可以通过复用Function/Method达到简化Main函数当中的目的。一般而言,方法名使用大写字母开头,如下示范Method的使用:

using System;
​
namespace Program{
    class myProgram{
        static void Main(string[] args){
        Console.Write("请输入你的姓名:");
        string name;
        name=Console.ReadLine();
        SayHi(name); //调用SayHi方法
        Console.ReadLine();
        
        
        static void SayHi(string userName){
            Console.WriteLine("hello!"+userName);
        }        
        
            }
}

可以看到上面我们使用的是void关键字,这个关键字代表函数不会返回任何值,如果我们的函数将要返回一个值,我们可以用return关键字来表达,下面是一个示范:

class myProgram{
        static void Main(string[] args){
        Console.Write("请输入数字:");
        int num=Convert.ToInt32(Console.ReadLine()); //需要使用convert转换为数字,不能直接ToInt,而是ToInt32
        int cubeNum=cube(num);
        Console.WriteLine(cubeNum);
        Console.ReadLine();   
        }
        static int cube(int num){
            return num*num;  //返回该数字的平方
        }
}

语句

c#中的if\switch\while\do while语句用法与js中相同,可以使用&&、||

for循环中注意声明变量不是使用let/var,而是根据变量的数据类型,以下是一个常见的打印数组各类数据项的for循环:

static void Main(string[] args){
       int[] nums={1,9,7,5,3}
​
       for(int i=0;i<nums.Length;i++){  //c#的length要大写
        Console.WriteLine(nums[i])
       }
​
        Console.ReadLine();
        }

C#调试与错误捕获

  • 错误捕获

在C#中也可以使用try...catch进行错误捕获,其中catch可以根据Exception对象的不同catch多次,也可以使用finally关键字

try{
//需要执行的代码
        }
        catch(Exception e){ //也可以使用其他更为细节的exception
            Console.WriteLine(e.Message);//打印错误信息
        }
        catch(FormatException e){//格式错误
            Console.WriteLine(e.Message);
        }
        finally{
            //最终总是会执行always execute
             Console.ReadLine();
​
        }
  • 调试

    预处理器#,在编译开始之前对信息进行预处理,如果计划发布两个版本的代码,即基本版本和有更多功能的企业版本,就可以使用这些预处理器指令来控制。一般使用#define 与其他处理器配合使用。

    #define Test   //测试版本
    using System;
    namespace TestApp{
        class Program{
            static void Main(string[] args){
                #if (Tset)
                    .....//进行操作
                #error  //生产错误
                #warning //生成警告
            }
        }
    }