c#基础知识
Hello World
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions
//Compiler version 4.0, .NET Framework 4.5
namespace Hello
{
public class HelloWorld
{
public static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
using表示使用命名空间,类似于Java中的导包,using System;之后就可以使用命名空间System中的所有类了。
在创建类的时候,需要指定类所属的命名空间,比如此处指定命名空间为Hello。Main函数即主函数,是程序的入口函数,可以看出和Java是很类似的。
示例程序中简单打印了一条Hello,World!语句,用到了Console类的WriteLine()方法,即在控制台打印一行语句,自动换行。这里的Console类属于命名空间System。
在用Visual Studio新建类文件时,默认的命名空间是当前文件所在的目录,比如
TestProject.Hello。事实上,命名空间和文件目录没有必然的联系,但为了不引起不必要的混淆,Visual Studio会将文件所在目录作为命名空间。
关键字
示例程序中如using,namespace,public,class,static,void,string等都属于c#的关键字,变量的命名不能和关键字冲突。c#中的关键字都是小写的,而且c#是大小写敏感的。
注释
- 单行注释:用两条斜线
//表示。 - 多行注释:以
/*开始,以*/结束,比如
```
/*
- 第一行注释
- 第二行注释
*/
```
- 文档注释:写在类、方法或属性的前面,用三条斜线
///表示,比如////// 这是一个测试类 /// class Test {…}
常量
c#中用关键字const定义常量,比如:
const double PI = 3.141592653
常用数据类型
字符类型:char
字符串类型:string
整数类型:int
双精度浮点型:double
c#的float类型需要在数值后面加上后缀
f或F,如float x = 3.5F;。否则会因为尝试将一个double类型数值存储到float类型中而发生编译错误。
类型转换
- 自动类型转换:2中不同类型的数值运算,低精度类型会自动转换为高精度类型。比如
8+2.4,int型数值会自动转换为double类型,再相加运算。 - 强制类型转换:比如
int i = (int)3.0;
标识符命名规则
程序中的变量名、常量名、类名、方法名,都叫做标识符。C#有一套标识符的命名规则,如果命名时不遵守规则,就会出错。这套规则简单说有下面三条:
- 标识符只能由英文字母、数字和下划线组成,不能包含空格和其他字符。
- 变量名不能用数字开头。
- 不能用关键字当变量名。
运算符
赋值运算符
=、+=、-=、*=、/=、%=
连续赋值,如x = y = 2;
算术运算符
基本的加+、减-、乘*、除/、求余%
+运算符还可以起到字符串连接作用,比如"my age is " + 18
自增++、自减--
比较运算符
=、!=、>、<、>=、<=
比较运算的结果,都是布尔类型bool,取值为true和false。(打印时是True、False)
逻辑运算符
逻辑运算符用来连接多个bool类型的表达式,实现多个条件的复合判断。包括:逻辑非!、逻辑与&&、逻辑或||
运算符优先级
运算符优先级顺序:
- 括号
- 一元运算符:
++、--、! *、/、%+、->、<、>=、<===、!=&&||- 赋值运算符
条件控制结构
if-else结构
if...else结构:
if (a > 0)
{
Console.WriteLine('Right');
}
else
{
Console.WriteLine('Wrong');
}
if...else if...else结构:
if (a > 0)
{
Console.WriteLine('Right');
}
else if (a == 0)
{
Console.WriteLine('Wait');
}
else
{
Console.WriteLine('Wrong');
}
如果条件分支中只包含一条命令,那么可以省略大括号,比如:
if (a > 0)
Console.WriteLine('Right');
else if (a == 0)
Console.WriteLine('Wait');
else
Console.WriteLine('Wrong');
当出现多个 if 和 else ,又没有{}来界定范围时,请参考下面2条原则:
- 每一个 else 与前面离它最近的 if 配对。
- 多个 else 都与同一个 if 相近时,最内层的 else 优先配对。
三元条件运算符
条件表达式 ? 分支1 : 分支2
当条件表达式为true时,执行分支1,为false时,执行分支2。
remark = age >= 18 ? "成年人" : "未成年人";
switch结构
int n1 = 3, n2 = 6;
char oper = '*';
switch(oper)
{
case '+': Console.Write(n1 + n2); break;
case '-': Console.Write(n1 - n2); break;
case '*': Console.Write(n1 * n2); break;
case '/': Console.Write(n1 / n2); break;
default: Console.Write("运算符错误"); break;
}
switch中的变量只能是3中类型:int、char、string
循环结构
while循环
int y = 5;
while (y > 0)
{
Console.Write(y+" ");
y--;
}
do…while循环
int y = 5;
do
{
Console.Write(y+" ");
y--;
}
while (y > 0);
for循环
for (int y=5; y>0; y--){
Console.Write(y+" ");
y--;
}
continue和break
continue关键字可以跳过本次循环,直接进入下次循环
for (int x = 1; x < 10; x++)
{
// 只打印奇数
if (x % 2 == 0)
continue;
Console.Write(x);
}
break关键字可以直接结束整个循环
int x = 1;
while(true):
{
Console.Write(x);
x++;
if (x > 5)
break;
}
数组
声明:
数据类型[ ] 数组名 = new 数据类型[长度];
多种初始化方式:
char[] a = new char[3];
char[] b = new char[]{'A', 'B', 'C'};
char[] c = {'A', 'B', 'C'};
char[] d = new char[3]{'A', 'B', 'C'}; //三行语句等效
数组通过 Length属性返回数组长度:
string[] names = new string[3]{"Tom", "Bob", "John"};
for(int i=0; i
foreach循环
string[] t =new string[]{"C","Sh","a","rp"};
foreach (string x in t)
{
Console.Write(x);
}
二维数组
二维数组的声明:
int[,] arr = new int[2, 3];
二维数组的赋值和取值:
arr[1, 0] = 28;
Console.Write(arr[1, 0]);
控制台接收输入
string name = Console.ReadLine();
int age = int.Parse(Console.ReadLine());
断点调试
打断点:快捷键F9或者在要打断点的行左边双击。
F5调试程序,F10单步执行,F11进入执行的代码(属性内部,方法内部)。
面向对象
类定义
class Child
{
public string _name;
public string _sex;
public int _age;
public int _height;
public void PlayBall()
{
Console.Write("Play football!");
}
}
实例化对象
Child xiaoMing = new Child();
xiaoMing._name = "小明";
xiaoMing._sex = "男";
xiaoMing._age = 6;
xiaoMing._height = 120;
Console.WriteLine("我叫" + xiaoMing._name);
xiaoMing.PlayBall();
访问修饰符
- public:公共
- private:私有
封装
当有些字段不应该被直接访问时,就可以使用封装的手段隐藏该字段,但是会提供访问该字段的接口,也就是访问器。c#中使用属性用于字段的公开访问:
class Child
{
private string _sex; //隐藏字段
public string Sex //公开属性(访问器)
{
get{return _sex;} //读
set{_sex = value;} //写(如果不提供写方法,那么这个属性就是只读属性)
}
}
属性的类型应该和它对应的字段相同,属性的命名规范应该尽可能和它对应的字段名相近,但是首字母需要大写。
VS中封装的快捷键,选中某个字段,然后点击:CTRL + R + E
利用属性赋值和取值:
Child xiaoMing = new Child();
xiaoMing.Sex = "男";
Console.Write(xiaoMing.Sex);
通过set块约束属性赋值
class Child
{
private int _age;
public int Age
{
get{return _age;}
set
{
//年龄限制为3-7岁
if(value>=3 && value<=7)
age = value;
}
}
}
方法重载
///
/// 吃糖
///
/// 糖的名称
public void EagSugar(string sugar)
{
Console.WriteLine("Eat " + sugar);
}
///
/// 吃糖. 同一个类中,多个方法名字相同但参数(类型或数量)不同
///
/// 糖的数量
public void EatSugar(int count)
{
if(count > 3)
{
Console.WriteLine("Eat too much!");
}
}
构造方法
如果没有显示定义构造方法,则会有一个默认的无参数的构造方法
如果显示定义了构造方法,默认的无参构造方法就没有了。类中一定包含一个无参构造方法,所以如果定义了其他构造方法,需要显式的写一个无参构造方法。
可以存在多个参数不同的重载构造方法。
class Child
{
private string _name;
private string _sex;
private int _age;
private int _height;
// 构造方法
public Child()
{
}
public Child(string name)
{
Name = name;
}
public string Name
{
get{return _name;}
set{_name = value;}
}
}
this关键字
class Child
{
private string name;
private string sex;
private int age;
private int height;
// 构造方法
public Child()
{
}
public Child(string name, age)
{
Name = name;
this.age = age;
}
public string Name
{
get{return name;}
set{name = value;}
}
}
对象初始化器
Child xiaoMing = new Child(){Name = "小明", Sex = "男"}; //其实调用的无参构造方法
值类型和引用类型
- 值类型:int、char、double、bool
- 引用类型:类、数组、接口
需要注意的是,string属于类
值类型
值类型变量存储对象的值,赋值时会创建值的副本。修改任何一个副本,不会影响其他的副本。
比如:
int x = 5;
int y = x;
y--;
此时运算后的结果为:
x=5; y=4;
y的改变不会影响到x
引用类型
引用类型变量持有的是对象的引用,持有该对象引用的变量对该对象进行修改,也会影响到持有其引用的其他变量。
比如:
Child c1 = new Child();
c1.Name = "小明";
Child c2 = c1;
c2.Name = "小卡";
Console.WriteLine(c1.Name);
Console.WriteLine(c2.Name);
此时的输出结果为:
小明
小卡
c1和c2两个变量都持有同一个对象引用,他们所做的操作直接影响到对象。
结构
值类型(int, char, double, bool …)都属于结构类型(struct),也具有 字段、属性和方法。
结构struct的定义:
struct Dog
{
string _name;
public string Name
{
get{return _name;}
set{_name = value;}
}
public void Sing()
{
Console.WriteLine("Wang~");
}
}
结构struct的实例化:
Dog dog = new Dog();
dog.Name = "小白";
dog.Sing();
结构也可以不用实例化:
Dog dog;
dog.Name = "小白";
dog.Sing();
结构struct总结:
- 结构是值类型(类是引用类型)
结构中可以定义字段、属性和方法
结构中的字段不能赋初始值
- 结构中不能显示定义无参构造方法
- 结构类型的对象可以不实例化
枚举类型
enum Gender
{
男, 女
}
使用:
Child c1 = new Child("小明", Gender.男, 6);
Child c2 = new Child("小华", (Gender)0, 5); //用枚举值转换
- 枚举是值类型
- 枚举中不能定义字段属性和方法
- 枚举值是从0递增的整数
ref关键字
值类型和引用类型在方法中的调用:
static void Main(string[] args)
{
Child c1 = new Child("小明", 5);
Growth(c1); //按引用传参,方法修改形参,通常实参也会被修改
Console.Write(c1.Age);
Growth(c1.Age); //按值传参,方法修改形参,实参不会被修改
Console.Write(c1.Age);
}
static void Growth(Child child) //引用类型参数,按引用传参
{
child.Age++;
}
static void Growth(int age) //值类型参数,按值传参
{
age++;
}
上面的代码可以看出,在按值传参时,参数传递的是变量的值,方法中对形参的改变不会影响到实参。
ref关键字可以让值类型参数按引用传参:
static void Main(string[] args)
{
int age = 3;
Growth(ref age); //传递引用
Console.Write(age);
}
static void Growth(ref int age) //值类型参数,按引用传参
{
age++;
}
out关键字
out关键字也是按引用传递,可以用来处理多个方法返回值:
static void Main(string[] args)
{
int age = 3;
Growth(ref age);
Console.Write(age);
}
static void Growth(int age)
{
age++;
}