基本概念

C#程序结构

一个完整的C#程序包含以下:

  • 命名空间声明(Namespace declaration)
  • 一个 class
  • Class 方法
  • Class 属性
  • 一个 Main 方法
  • 语句(Statements)& 表达式(Expressions)
  • 注释
    C# 文件的后缀为 .cs。
    以下创建一个 test.cs 文件,文件包含了可以打印出 “Hello World” 的简单代码:
using System;
namespace HelloWorldApplication
{
class HelloWorld
{
static void Main(string[] args)
{
/* 我的第一个 C# 程序*/
Console.WriteLine("Hello World");
Console.ReadKey();
}
}
}

让我们看一下上面程序的各个部分:

  • 程序的第一行 using System; - using 关键字用于在程序中包含 System 命名空间。 一个程序一般有多个 using 语句。

  • 下一行是 namespace 声明。一个 namespace 里包含了一系列的类。HelloWorldApplication 命名空间包含了类 HelloWorld。

  • 下一行是 class 声明。类 HelloWorld 包含了程序使用的数据和方法声明。类一般包含多个方法。方法定义了类的行为。在这里,HelloWorld 类只有- 一个 Main 方法。

  • 下一行定义了 Main 方法,是所有 C# 程序的 入口点。Main 方法说明当执行时 类将做什么动作。

  • 下一行 // 将会被编译器忽略,且它会在程序中添加额外的 注释。

  • Main 方法通过语句 Console.WriteLine(“Hello World”); 指定了它的行为。

  • WriteLine 是一个定义在 System 命名空间中的 Console 类的一个方法。该语句会在屏幕上显示消息 “Hello World”。

  • 最后一行 Console.ReadKey(); 是针对 VS.NET 用户的。这使得程序会等待一个按键的动作,防止程序从 Visual Studio .NET 启动时屏幕会快速运行并关闭。

以下几点值得注意:

  1. C# 是大小写敏感的。
  2. 所有的语句和表达式必须以分号(;)结尾。
  3. 程序的执行从 Main 方法开始。
  4. 与 Java 不同的是,文件名可以不同于类的名称。

    类 (Class)

    对象 (Object)

    属性 (Properties)

    方法 (Methods)

    // 类
    public class Person
    {
    // 字段
    private string name;
    private int age;

    // 属性
    public string Name
    {
    get { return name; }
    set { name = value; }
    }

    public int Age
    {
    get { return age; }
    set { age = value; }
    }

    // 方法
    public void Display()
    {
    Console.WriteLine($"Name: {name}, Age: {age}");
    }
    }
    在这个例子中,Person类有两个字段:name和age,它们分别用于存储人的姓名和年龄。这两个字段被声明为private,意味着它们只能在Person类内部被访问。

类还定义了两个属性:Name和Age,它们提供了对私有字段的公共访问。这是通过get和set访问器来实现的,它们分别用于获取和设置属性的值。

最后,类定义了一个Display方法,它用于在控制台上显示人的姓名和年龄。

事件 (Events)

在C#中,事件(Event)是一种使类或对象能够提供通知的机制。当类中发生某些特定的事情时,类可以触发事件,以通知其他类或对象。这是一种实现松散耦合的方式,因为触发事件的类不需要知道哪些类或对象会接收(或“监听”)该事件。
以下是如何在C#中声明、触发和监听事件的基本步骤:

  • 声明事件

在类中,你需要使用event关键字来声明一个事件。通常,事件是基于某个委托(Delegate)类型的,该委托定义了事件处理方法的签名。

public class MyEventClass
{
// 声明委托
public delegate void MyEventHandler(string message);

// 声明事件
public event MyEventHandler MyEvent;

// 触发事件的方法
protected virtual void OnMyEvent(string message)
{
MyEventHandler handler = MyEvent;
handler?.Invoke(message);
}
}

  • 触发事件

在类的某个方法中,你可以通过调用OnMyEvent方法来触发事件。这将调用所有已注册的事件处理程序。

public void DoSomething()
{
// 做一些事情...

// 然后触发事件
OnMyEvent("Something happened!");
}

  • 监听事件

在其他类或对象中,你可以监听MyEventClass类的事件。为此,你需要创建一个与事件委托签名相匹配的方法,并将该方法与事件相关联。

public class EventListener
{
public void ListenForEvent(MyEventClass myEventClass)
{
// 将事件处理程序与事件相关联
myEventClass.MyEvent += MyEventHandler;

// 现在,当myEventClass触发MyEvent时,MyEventHandler将被调用
}

private void MyEventHandler(string message)
{
Console.WriteLine($"Event received: {message}");
}
}
  • 使用

最后,你可以创建MyEventClass和EventListener的实例,并将它们连接起来。

MyEventClass myEventClass = new MyEventClass();
EventListener eventListener = new EventListener();

// 开始监听事件
eventListener.ListenForEvent(myEventClass);

// 触发事件
myEventClass.DoSomething();
// 输出:Event received: Something happened!

委托 (Delegates)

在C#中,委托(Delegate)是一种特殊的类型,它定义了方法的签名,使得可以将具有相同签名的方法作为参数传递,或者将方法赋值给变量。委托是事件和回调方法的基础,非常适用于实现回调函数、事件监听和异步编程等模式。

  • 委托的声明

委托的声明类似于方法的声明,但不包含方法体,且使用delegate关键字。例如:

public delegate void MyDelegate(string message);

这里声明了一个名为MyDelegate的委托,它定义了一个接受单个string类型参数并返回void的方法签名。

  • 委托的实例化

委托可以通过将具有相同签名的方法作为其构造函数的参数来实例化。例如:

public class MyClass
{
public static void MyMethod(string message)
{
Console.WriteLine(message);
}
}

// ...

MyDelegate myDelegate = new MyDelegate(MyClass.MyMethod);

这里,MyDelegate实例myDelegate被赋值为指向MyClass.MyMethod方法的引用。

  • 委托的调用

一旦委托被实例化并指向了一个或多个方法,它就可以像普通方法一样被调用。例如:

myDelegate("Hello, World!");

这将调用MyClass.MyMethod方法,并传递字符串”Hello, World!”作为参数。

  • 委托的多播

委托的一个强大功能是它们可以组合多个方法,形成多播委托(Multicast Delegate)。当多播委托被调用时,其包含的所有方法都将依次被调用。例如:

public class AnotherClass
{
public static void AnotherMethod(string message)
{
Console.WriteLine($"Another class says: {message}");
}
}

// ...

MyDelegate anotherDelegate = new MyDelegate(AnotherClass.AnotherMethod);
MyDelegate combinedDelegate = myDelegate + anotherDelegate;

combinedDelegate("Hello, Multicast!");

这将依次调用MyClass.MyMethod和AnotherClass.AnotherMethod,传递相同的字符串参数。

  • 委托的用途

    委托在C#编程中非常有用,特别是在以下场景中:

    • 实现事件和回调机制。
    • 将方法作为参数传递给其他方法。
    • 实现异步编程模式,如使用BeginInvoke和EndInvoke方法进行异步方法调用。
    • 在LINQ查询和表达式树中作为表达式的一部分。

    接口 (Interfaces)

数据类型

值类型 (Value Types)

值类型变量可以直接分配给一个值。它们是从类 System.ValueType 中派生的。
值类型直接包含数据。比如 int、char、float,它们分别存储数字、字符、浮点数。当您声明一个 int 类型时,系统分配内存来存储值。

整型 (int, long, short, etc.)

浮点型 (float, double)

字符型 (char)

布尔型 (bool)

类型 描述 范围 默认值
bool 布尔值 True 或 False False
byte 8 位无符号整数 0 到 255 0
char 16 位 Unicode 字符 U +0000 到 U +ffff ‘\0’
decimal 128 位精确的十进制值,28-29 有效位数 (-7.9 x 1028 到 7.9 x 1028) / 100 到 28 0.0M
double 64 位双精度浮点型 (+/-)5.0 x 10-324 到 (+/-)1.7 x 10308 0.0D
float 32 位单精度浮点型 -3.4 x 1038 到 + 3.4 x 1038 0.0F
int 32 位有符号整数类型 -2,147,483,648 到 2,147,483,647 0
long 64 位有符号整数类型 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 0L
sbyte 8 位有符号整数类型 -128 到 127 0
short 16 位有符号整数类型 -32,768 到 32,767 0
uint 32 位无符号整数类型 0 到 4,294,967,295 0
ulong 64 位无符号整数类型 0 到 18,446,744,073,709,551,615 0
ushort 16 位无符号整数类型 0 到 65,535 0

引用类型 (Reference Types)

引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。
换句话说,它们指的是一个内存位置。使用多个变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由一个变量改变的,其他变量会自动反映这种值的变化。内置的 引用类型有:object、dynamic 和 string。

对象(Object)类型

对象(Object)类型 是 C# 通用类型系统(Common Type System - CTS)中所有数据类型的终极基类。Object 是 System.Object 类的别名。所以对象(Object)类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。

当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。

object obj;
obj = 100; // 这是装箱

动态(Dynamic)类型

您可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。

声明动态类型的语法:

例如

dynamic d = 20;

字符串 (String)

字符串(String)类型 允许您给变量分配任何字符串值。字符串(String)类型是 System.String 类的别名。它是从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号和 @引号。

例如:

String str = "runoob.com";

一个 @引号字符串

@"runoob.com";

C# string 字符串的前面可以加 @(称作”逐字字符串”)将转义字符(\)当作普通字符对待,比如:

string str = @"C:\Windows";
\\等价于:
string str = "C:\\Windows";

@ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内。

string str = @"<script type=""text/javascript"">
<!--
-->
</script>";

指针类型(Pointer types)

指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。

声明指针类型的语法:

char* cptr;
int* iptr;

类 (Class)

接口 (Interface)

数组 (Array)

控制结构

条件语句 (if, else if, else)

循环 (for, foreach, while, do-while)

分支 (switch, case)

跳转 (break, continue)

面向对象编程 (OOP)

封装 (Encapsulation)

继承 (Inheritance)

多态 (Polymorphism)

异常处理

try-catch

finally

throw

集合与泛型

List

Dictionary<TKey, TValue>

其他集合类型…

文件与IO操作

文件读写

目录操作

路径操作

异步编程

async/await

Task

线程 (Thread)

网络编程

HTTP请求

Socket编程

其他网络操作

其他高级特性

LINQ

反射 (Reflection)

属性 (Attributes)

并发编程