C#语法速览
C#是.net Franmework下的一门编程语言,语法与c类似。
命令行编译:csc
需要配置环境变量path:C:\Windows\Microsoft.NET\Framework64\v4.0.30319
VScode编写
- 需要安装.net core sdk和c#插件
相关快捷键:ctrl+`,打开终端(命令行)
- 打开终端
- 键入
dotnet new console
. - 运行
dotnet run
程序结构
一个C#程序主要包括主要包括以下部分:
- 命名空间声明(Namespace declaration)
- 一个class
- Class方法
- Class字段
- 一个Main方法
- 语句(statements) & 表达式(expressions)
- 注释
用法:
- 编译生成File.exe
csc File.cs
- 编译生成My.exe
csc /out:My.exe File.cs
基本语法
注释
多行注释以/* */开头结尾,单行注释以//开头。
/* This program demonstrates
The basic syntax of C# programing Language */
// end.
数据类型
- 值类型
- 结构是值类型。
常用的有
类型 | 默认值 |
---|---|
bool | False |
byte | o |
char(unicode字符) | ‘\0’ |
decimal(128位) | 0.0M |
double | 0.0D |
float | 0.0F |
int | 0 |
long | 0L |
short(16位) | 0 |
uint(无符号) | 0 |
d/m/f/l大小写均可
注意: c#中,bool不能转换为int。
注:以下的type(T)指以上任意一种类型。
查看大小:sizeof(type) retVal:byte(s)
一个值类型转换为对象类型,称为装箱;一个对象类型转换为值类型,则被称为拆箱。
int val=8;
object obj=val;
int nval=(int)obj;
- 引用类型
- 未被new创建的的引用类型为null。
- object 是所有数据类型的终极基类。是System.Object 类的别名。
- danamic 可以储存任意类型的值,类型检查在运行时发生。
- string
//常用方法
Replace,ToUpper,ToLower,Trim,Split,IndexOf
//属性:Length
public static string Format( string format, Object arg0 )
//前缀@表示不转义。
- 指针类型
- type* identifier;
类型转换
- 隐式类型转换:向宽转换。(int->double,子类到基类)
- 强制类型转换:
(type)var
,舍弃小数。- 对象的
ToType()
方法。 Convert.ToType(var)
静态方法(比下面一个转换的范围广,四舍六入逢五凑偶)。int.Parse(str)
静态方法。int.TryParse(string s,out int i)
静态方法,返回boo值,out为输出关键字,转换失败输出0;
允许变量在定义时初始化。
常量
- 整数常量
- 前缀0x/0X十六进制,0八进制
- 后缀U,L表示unsigned和long。
定义: const type var=value;
运算符与表达式
- 算数运算符
+ - * /(整数为整除) % ++ --
- 关系运算符
== != > < >= <=
- 逻辑运算符
&& || !
- 位运算符
& | ^ ~ << >>
- 赋值运算符
= += -= *= /= %= <<= >>= &= ^= |=
- 其他运算符
sizeof(T),typeof(T),&,*,?,x is T(如果x是T返回true,否则返回false),x as T(返回类型为T的x,如果类型不是T,返回null),default(T)(获取类型的默认值)
- 匿名函数
(T x)=>y
流程
//判断语句
textexpr ? expr1:expr2;
if(textexpr1)
expr1;
else if(textexpr2)
expr2;
else
expr3;
switch(expression)
{
case constant-expr:
expr;
break;
default:
exprn;
break;
}
//循环语句
while(condition)
expr;
break;
continue;
for(init;condition;increment)
expr;//在init声明的对象作用于整个块;
foreach(type element in array)
expr;
//goto语句
goto check;
check:
x++;
数组
//声明数组
type[] arrayName;
//初始化数组
double[] balance=new double[10];//全部初始化为默认值
double[] balance={23.0,423.3,25.3};//声明的同时赋值
int[] marks=new int[5]{99,98,92,96,95};//与下式等价
int[] marks=new int[]{99,98,92,96,95};
int[] score=marks;//指向相同的地址。
string[,] names;
int [,] a = new int [3,4] {
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};
//Array类的方法
Array.Reverse(marks)
Array.Sort(marks)
结构
结构的成员默认是公有的。
struct Books
{
public string title;
public string author;
public string subject;
public int book_id;
};
枚举
//枚举列表中的每个符号代表一个整数值,一个比它前面的符号大的整数值。
//默认情况下,第一个枚举符号的值是 0
enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };
文件
FileStream F = new FileStream("sample.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
文件属性操作 File类与FileInfo都能实现。静态方法与实例化方法的区别
//use File class
Console.WriteLine(File.GetAttributes(filePath));
File.SetAttributes(filePath,FileAttributes.Hidden | FileAttributes.ReadOnly);
Console.WriteLine(File.GetAttributes(filePath));
//user FilInfo class
FileInfo fi = new FileInfo(filePath);
Console.WriteLine(fi.Attributes.ToString());
fi.Attributes = FileAttributes.Hidden | FileAttributes.ReadOnly; //隐藏与只读
Console.WriteLine(fi.Attributes.ToString());
//只读与系统属性,删除时会提示拒绝访问
fi.Attributes = FileAttributes.Archive;
Console.WriteLine(fi.Attributes.ToString());
函数
有四类参数,值参数,引用参数,输出参数,参数数组。
- 引用传参关键字
ref
(调用方和被调方两边都要加) - 输出传参关键字
out
(两边都要加,与引用的区别,调用时无需声明(不要求向调用方提供的自变量显式赋值)) - 参数数组关键字
params
- 局部变量必须明确赋值
using System;
class Example
{
static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
public static void SwapExample()
{
int i = 1, j = 2;
Swap(ref i, ref j);
Console.WriteLine($"{i} {j}"); // Outputs "2 1"
}
static void Divide(int x, int y, out int result, out int remainder)
{
result = x / y;
remainder = x % y;
}
public static void OutUsage()
{
Divide(10, 3, out int res, out int rem);
Console.WriteLine("{0} {1}", res, rem); // Outputs "3 1"
}
}
public class Console
{
public static void Write(string fmt, params object[] args) { }
public static void WriteLine(string fmt, params object[] args) { }
// ...
}
Console.WriteLine("x={0} y={1} z={2}", x, y, z);
string s = "x={0} y={1} z={2}";//与下式等价
object[] args = new object[3];
args[0] = x;
args[1] = y;
args[2] = z;
Console.WriteLine(s, args);
封装 类
- 访问修饰符:
Public,Private,Protected,Internal(同一程序集内),Protected internal
- 访问标识符 /
指定了对类及其成员的访问规则。如果没有指定,则使用默认的访问标识符。类的默认访问标识符是 internal,成员的默认访问标识符是 private -
静态标识符:static,静态变量被初始化为默认值。
- 只读标识符:readonly
- 定义方法
<Access Specifier><Return Type><Method Name>(Parameter List)
- 可空类型
- 定义:
<data_type>? <varname>=null
,可以被赋null值 - null合并运算符:
??
,null合并运算符为类型转换定义了一个预设值。
- 定义:
- 只有在基类的嵌套派生类中,私有成员才可见。
double? num1=null; double? num2=3.14159; double num3; num3=num1 ?? 5.34;//5.34 num3=num2 ?? 5.34;//3.14159
继承
- this:指向实例本身
- base:指向实例的父类
class Program
{
static bool done=false;
static readonly object locker = new object();
static void Main(string[] args)
{
double[] balance = { 23.0, 423.3, 25.3 };//与下式等
double b;
b = 1l;
string s=null;
Console.WriteLine(s);
Console.ReadKey();
}
}
public class Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
public class Point3D : Point
{
public int z;
public Point3D(int x, int y, int z) :
base(x, y)//方法也可以继承
{
this.z = z;
}
}
接口
- 关键字:
interface
接口口定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 “是什么” 部分,派生类定义了语法合同 “怎么做” 部分。
接口定义了可由类和结构实现的协定。 接口可以包含方法、属性、事件和索引器。 接口不提供所定义的成员的实现代码,仅指定必须由实现接口的类或结构提供的成员。
接口使得实现接口的类或结构在形式上保持一致。
虚类和抽象类
- 虚方法、重写方法和抽象方法
如果实例方法声明中有 virtual 修饰符,可以将实例方法称为“虚方法”。 如果没有 virtual 修饰符,可以将实例方法称为“非虚方法”。
调用虚方法时,为其调用方法的实例的运行时类型决定了要调用的实际方法实现代码。 调用非虚方法时,实例的编译时类型是决定性因素。
可以在派生类中重写虚方法。 如果实例方法声明中有 override 修饰符,那么实例方法可以重写签名相同的继承虚方法。 但如果虚方法声明中引入新方法,重写方法声明通过提供相应方法的新实现代码,专门针对现有的继承虚方法。
抽象方法是没有实现代码的虚方法。 抽象方法使用 abstract 修饰符进行声明,只能在同样声明了 abstract 的类中使用。 必须在所有非抽象派生类中重写抽象方法。
C# 允许您使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。
请注意,下面是有关抽象类的一些规则:
- 不能创建一个抽象类的实例。
- 不能在一个抽象类外部声明一个抽象方法。 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。
区别与联系:
- 虚方法要实现。虚方法必须有实现部分,并为派生类提供了重写该方法的选项。抽象方法没有提供实现部分,抽象方法是一种强制派生类重写的方法,否则派生类将不能被实例化。
//抽象方法
public abstract class Animal
{
public abstract void Sleep();
public abstract void Eat();
}
//虚方法
public class Animal
{
public virtual void Sleep(){}
public virtual void Eat(){}
}
-
有抽象方法的类必须声明为抽象类。抽象方法只能在抽象类中声明, 抽象方法必须在派生类中重写(override)。虚方法不是也不必要重写。其实如果类包含抽象方法,那么该类也是抽象的,也必须声明为抽象的。
-
两者重写都用override关键字。
高级特性
lambda表达式
lambda表达式是一个简短的函数
(input-parameters)=>expression//(当参数为一个时,括号可以省略)
(x,y)=>x==y
(int x, string s)=> s.Length>x//如果无法推断类型
泛型
运算符重载
public static Box operator+ (Box b, Box c)
{
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
异常
try
{
// 引起异常的语句
}
catch( ExceptionName e1 )
{
// 错误处理代码
}
catch( ExceptionName e2 )
{
// 错误处理代码
}
catch( ExceptionName eN )
{
// 错误处理代码
}
finally
{
// 要执行的语句
}