C# 是一种面向对象的语言,还进一步支持面向组件的编程。
C# 采用统一的类型系统。 所有 C# 类型(包括 int 和 double 等基元类型)均继承自一个根 object 类型。
C# 语言忽略缩进和空格,因此;
是必须的(除了方法和访问器块之后不需要;
)。
一个简单的HelloWorld
此类的完全限定的名称为HelloWorldApplication .HelloWorld
using System;//引用外部命名空间
namespace HelloWorldApplication //声明自身命名空间
{
class HelloWorld
{
static void Main(string[] args) //声明Main方法,这是所有C#程序的入口
{
/* 我的第一个 C# 程序*/
Console.WriteLine("Hello World");
Console.ReadKey();//等待按键,防止运行结束后程序关闭
}
}
}
- 在任何 C# 程序中的第一条语句都是:
using System;
通过using
关键字引用命名空间,即可使用其中包含的公共类型和成员。 - 标识符
标识符必须以字母、下划线或 @ 开头,不能含有$,不能与关键字或C#的类库名称相同
数据类型
C# 有两种类型:值类型和引用类型。 值类型的变量直接包含数据,而引用类型的变量则存储对数据(称为“对象”)的引用。 对于引用类型,两个变量可以引用同一对象;因此,对一个变量执行的运算可能会影响另一个变量引用的对象。 借助值类型,每个变量都有自己的数据副本;因此,对一个变量执行的运算不会影响另一个变量(ref
和 out
参数变量除外)。
值类型
所有值类型均隐式继承自 ValueType
,后者又隐式继承自 object
。
- [简单类型]
- 有符号的整型:
sbyte
、short
、int
、long
- 无符号的整型:
byte
、ushort
、uint
、ulong
- Unicode 字符:
char
- IEEE 二进制浮点:
float
、double
- 高精度十进制浮点数:
decimal
(用于财务计算。可以通过在一个浮点类型的值后加M
或m
声明。) - 布尔:
bool
- 有符号的整型:
- [枚举类型]
- 格式为
enum E {...}
的用户定义类型
- 格式为
- [结构类型]
- 格式为
struct S {...}
的用户定义类型
- 格式为
- [可以为 null 的值类型]
- 值为
null
的其他所有值类型的扩展
- 值为
引用类型
- [类类型]
- 其他所有类型的最终基类:
object
- Unicode 字符串:
string
- 格式为
class C {...}
的用户定义类型
- 其他所有类型的最终基类:
- [接口类型]
- 格式为
interface I {...}
的用户定义类型
- 格式为
- [数组类型]
- 一维和多维,例如
int[]
和int[,]
- 一维和多维,例如
- [委托类型]
- 格式为
delegate int D(...)
的用户定义类型
- 格式为
对象(Object)类型
是所有数据类型的终极基类。Object
是 System.Object
类的别名。对象类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。
在分配值之前,需要先进行类型转换。当一个值类型转换为对象类型时,则被称为 装箱
;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱
。
String i="abc";
object obj=(object)i;//装箱
object obj2="abc";
string i2=(string)obj2;//拆箱
动态(Dynamic)类型
可存储任何类型的值在动态数据类型变量中。这些变量的类型约束是在运行时发生的,被编译后本质是一个Object
类型。 而var
关键字在编译时静态的定义数据类型,而不是在运行时,其本质上是个语法糖,一旦被编译,编译器就会自动匹配var
变量的实际类型。
dynamic d = 20;
double result = 5 / 3;
Console.WriteLine(result);//1
var result2 = (double)5 / 3;
Console.WriteLine(result2);//1.66666666666667
字符串(String)类型
- 字符串前加
@
(称作逐字字符串
)将转义字符(\)当作普通字符对待。@ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内(类似js中的``
)。 - 字符串前加
$
(称作内插字符串
)比起复合格式设置字符串
更清晰易读。 -
string
只是String
类型的别名。
String str = "runoob.com";
string str = @"C:\Windows";//string str = "C:\\Windows";
string str = @"<script type=""text/javascript"">
</script>";
string name = "Mark";
var date = DateTime.Now;
// 复合格式设置字符串:
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// 内插字符串:
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");
- 空字符串
string s = String.Empty;
获取实例的类型 .GetType()
不能对null使用,null没有类型
Console.WriteLine(10.GetType());//System.Int32
类型转换(变量本身的数据类型不变)
- 隐式类型转换,仅能子类转化为基类
- 显式类型转换,需要强制转换运算符
- (int)a中,a仅能为数字
- Convert.ToXXX(a)可以实现基本类型间的各种转换
- 字符串类型转换为对应的基本类型用
类型名.Parse()
方法,基本类型转化成字符串用.ToString()
double a = 123.11;
int b = 555;
b = (int)a;
var c = Convert.ToInt32(a);
var d = a.ToString();
var e = Int32.Parse(d);
可空类型 Nullable
对于所有不可为 null
的值类型 T
,都有对应的可空类型 T?
或 Nullable<T>
,可以包含附加值 null
。
int? i = 3;
Nullable<int> i = new Nullable<int>(3);
判断是否为空
- 通过
==
和!=
可用于判断是否为空 - 只读属性
.HasValue
可用于判断一个可空值是否有值 - 只读属性
.Value
可用于获取一个可空值的值
int? x = 3;
int y;
if (x.HasValue) y = x.Value;
if (x != null) y = x.Value;
Null 合并运算符 ??
如果第一个操作数的值为 null,则运算符返回第二个操作数的值,否则返回第一个操作数的值。
此时被赋值的变量类型会变得允许为空,可用于将可空类型转变为基础类型(或使用.GetValueOrDefault()
方法)。
double? num = 3.14157;
double num1;
num1 = num ?? 5.34; // num 如果为空值则返回 5.34
Null 条件运算符
借助 ?.
和?[]
(null 条件)运算符,可轻松编写包含 null 值的逻辑,无需额外的 if 检查。
string s = null;
Console.WriteLine(s.Length);
char? c = s?[0];
Console.WriteLine(c.HasValue);
string s = null;
bool? hasMore = s?.ToCharArray()?.GetEnumerator()?.MoveNext();
Console.WriteLine(hasMore.HasValue);
string s = null;
bool hasMore = s?.ToCharArray()?.GetEnumerator()?.MoveNext() ?? false;
Console.WriteLine(hasMore);
获取变量/类/类成员的名称 nameof()
Console.WriteLine(nameof(System.String));//String
int j = 5;
Console.WriteLine(nameof(j));//j
List<string> names = new List<string>();
Console.WriteLine(nameof(names));//names
运算符
运算符优先级同js
- 算术运算符
+
-
*
/
%
++
--
- 关系运算符
-
>
<
>=
<=
可用于整数与浮点数之间 -
==
!=
只能比较完全相同类型的变量
-
- 逻辑运算符
&&
||
!
不同于js,只能直接比较布尔值,并返回布尔值 - 位运算符
<<
>>
&
^
|
~
- 赋值运算符
=
+=
-=
*=
/=
%=
<<=
>>=
&=
^=
|=
- 其他运算符
-
sizeof()
返回目标变量/类型的大小。 -
typeof()
返回 class 的类型。(对实例应使用.GetType()方法) -
&
返回变量的地址。 -
*
变量的指针。 -
?:
条件表达式。 -
is
判断对象是否为某一类型。(null 不属于任何类型) -
as
强制转换(不能应用在值类型数据)
-
Animal animal = new Animal() as Person;
语句
声明语句
变量
可以在声明时被初始化(赋予一个初始值)
int d = 3, f = 5;
d = Convert.ToInt32(Console.ReadLine());//其中Console.ReadLine()接收的总为字符串
常量
常量可以被当作常规的变量,只是它们的值在定义后不能被修改。
使用const定义常量
public const int c2 = c1 + 5;
选择语句
- if ... else if ... else
- switch
迭代语句
while
do...while
for 与js相同,for的
()
和{}
中均非局部作用域foreach
foreach(int i in new int[]{ 1, 2, 3 })
{
Console.WriteLine(i+5);
}
Console.ReadLine();//6 7 8
跳转语句
- break
- continue
- goto
static void GoToStatement(string[] args)
{
int i = 0;
goto check;
loop:
Console.WriteLine(args[i++]);
check:
if (i < args.Length)
goto loop;
}
- throw
- return
- yield
static System.Collections.Generic.IEnumerable<int> Range(int start, int end)
{
for (int i = start; i < end; i++)
{
yield return i;
}
yield break;
}
static void YieldStatement(string[] args)
{
foreach (int i in Range(-10,10))
{
Console.WriteLine(i);
}
}
异常处理
- try {...} catch(e){...} finally{}
其他语句
checked 和 unchecked 语句
用于控制整型类型算术运算和转换的溢出检查上下文。
static void CheckedUnchecked(string[] args)
{
int x = int.MaxValue;
unchecked
{
Console.WriteLine(x + 1); // Overflow
}
checked
{
Console.WriteLine(x + 1); // Exception
}
}
lock 语句
用于获取给定对象的相互排斥锁定,执行语句,然后解除锁定。
class Account
{
decimal balance;
private readonly object sync = new object();
public void Withdraw(decimal amount)
{
lock (sync)
{
if (amount > balance)
{
throw new Exception(
"Insufficient funds");
}
balance -= amount;
}
}
}
using语句
using
语句用于获取资源,执行语句,然后释放资源。
using
语句中使用的对象必须实现 IDisposable
接口(Windows内核对象、文件操作、数据库连接、socket、Win32API、网络等)。执行结束后会释放资源。
using
语句支持初始化多个变量,但前提是这些变量的类型必须相同
static void UsingStatement(string[] args)
{
using (Font font3=new Font("Arial",10.0f), font4=new Font("Arial",10.0f))
{
// Use font3 and font4.
}
}
-
using
实质
在程序编译阶段,编译器会自动将using
语句生成为try-finally
语句,并在finally
块中调用对象的Dispose
方法,来清理资源。所以,using
语句等效于try-finally
语句,例如:
using (Font f2 = new Font("Arial", 10, FontStyle.Bold))
{
font2.F();
}
被编译器翻译为:
Font f2 = new Font("Arial", 10, FontStyle.Bold);
try
{
font2.F();
}
finally
{
if (f2 != null) ((IDisposable)f2).Dispose();
}
Expression-Bodied立即返回表达式 和 lambda表达式
Expression-Bodied用于单个语句作为方法主体的方法定义:
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
public string FirstName
{
get => firstName;
set => firstName = value;
}
lambda表达式用于转换委托
Func<int, int> square = x => x * x;
...
Action<string> greet = name =>
{
string greeting = $"Hello {name}!";
Console.WriteLine(greeting);
};
greet("World");