C# 语言教程:语法、特性与应用详解

C# 语言教程:语法、特性与应用详解

C#(读作 "C Sharp")是由微软开发的一种现代、通用、面向对象的编程语言。它在 .NET 框架(现在主要是 .NET)上运行,也可用于跨平台的 .NET Core(现已合并为 .NET 5 及更高版本)开发。C# 以其强大的功能、类型安全、可扩展性和广泛的应用领域而闻名。本教程将深入探讨 C# 的语法、关键特性以及在各种应用场景中的实际应用。

一、C# 语言基础

1.1 第一个 C# 程序:Hello, World!

让我们从经典的 "Hello, World!" 程序开始,了解 C# 程序的基本结构:

```csharp
using System;

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
```

代码解析:

  • using System;: using 关键字用于导入命名空间。System 命名空间包含了许多常用的类和方法,如 Console 类。
  • class Program: C# 是面向对象的语言,所有代码都必须位于类中。Program 是我们定义的类名。
  • static void Main(string[] args): Main 方法是程序的入口点。
    • static: 表示 Main 方法是静态的,可以直接通过类名调用,无需创建类的实例。
    • void: 表示 Main 方法不返回任何值。
    • string[] args: Main 方法可以接收一个字符串数组作为命令行参数。
  • Console.WriteLine("Hello, World!");: Console.WriteLine 方法用于在控制台输出文本。

1.2 数据类型

C# 是一种强类型语言,每个变量都必须声明其数据类型。C# 的数据类型分为值类型和引用类型。

值类型 (Value Types): 值类型直接存储数据。

  • 整数类型:
    • int: 32 位有符号整数 (常用)
    • long: 64 位有符号整数
    • short: 16 位有符号整数
    • byte: 8 位无符号整数
    • sbyte: 8 位有符号整数
    • uint: 32 位无符号整数
    • ulong: 64 位无符号整数
    • ushort: 16 位无符号整数
  • 浮点数类型:
    • float: 32 位单精度浮点数
    • double: 64 位双精度浮点数 (常用)
    • decimal: 128 位高精度十进制数 (用于金融计算)
  • 字符类型:
    • char: 16 位 Unicode 字符
  • 布尔类型:
    • bool: 表示真 (true) 或假 (false)
  • 结构体(struct): 用户自定义值类型.
  • 枚举(enum): 一组命名的整数常量.

引用类型 (Reference Types): 引用类型存储数据的内存地址。

  • 类 (class): 面向对象编程的核心,用于定义对象的蓝图。
  • 接口 (interface): 定义一组方法、属性、事件和索引器,但不提供实现。
  • 数组 (array): 存储相同类型元素的集合。
  • 字符串 (string): 表示文本。
  • 委托 (delegate): 类型安全的函数指针。
  • 对象 (object): 所有类型的基类。

示例:

```csharp
int age = 30;
double price = 99.99;
char grade = 'A';
bool isEnabled = true;
string name = "John Doe";
int[] numbers = { 1, 2, 3, 4, 5 };

// 结构体示例
struct Point
{
public int X;
public int Y;
}
Point p = new Point { X = 10, Y = 20};

//枚举示例
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
Days today = Days.Wed;
```

1.3 变量和常量

  • 变量: 使用数据类型声明,用于存储数据。
    csharp
    int myVariable = 10;
    myVariable = 20; // 可以改变变量的值

  • 常量: 使用 const 关键字声明,一旦赋值后不能更改。
    csharp
    const double Pi = 3.14159;
    // Pi = 3.14; // 错误:不能修改常量的值

  • 只读字段: 使用 readonly 关键字声明, 只能在声明时或者构造函数中初始化.
    ```csharp
    class MyClass
    {
    readonly int myReadonlyField = 5;
    public MyClass(int val)
    {
    myReadonlyField = val; //可以在构造函数中赋值
    }
    }

    ```

1.4 运算符

C# 提供了丰富的运算符,用于执行各种操作。

  • 算术运算符: +, -, *, /, % (取模)
  • 关系运算符: ==, !=, >, <, >=, <=
  • 逻辑运算符: && (与), || (或), ! (非)
  • 赋值运算符: =, +=, -=, *=, /=, %=
  • 位运算符: & (按位与), | (按位或), ^ (按位异或), ~ (按位取反), << (左移), >> (右移)
  • 条件运算符 (三元运算符): condition ? expression1 : expression2
  • 类型运算符: is, as, typeof
  • 空合并运算符: ?? , ??=

示例:

```csharp
int a = 10;
int b = 5;
int sum = a + b; // 15
bool isEqual = a == b; // false
bool result = (a > b) && (b > 0); // true
int max = (a > b) ? a : b; // 10

string str = null;
string str2 = str ?? "default value"; // str2 的值为 "default value"

```

1.5 控制流语句

控制流语句用于控制程序的执行流程。

  • 条件语句:

    • if-else: 根据条件执行不同的代码块。
    • switch: 根据表达式的值执行不同的 case。
  • 循环语句:

    • for: 循环执行固定次数的代码块。
    • while: 当条件为真时循环执行代码块。
    • do-while: 至少执行一次代码块,然后在条件为真时继续循环。
    • foreach: 遍历集合中的每个元素。

示例:

```csharp
// if-else
int num = 10;
if (num > 0)
{
Console.WriteLine("Positive");
}
else if (num < 0)
{
Console.WriteLine("Negative");
}
else
{
Console.WriteLine("Zero");
}

// switch
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
// ... other cases
default:
Console.WriteLine("Invalid day");
break;
}

// for
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}

// while
int count = 0;
while (count < 5)
{
Console.WriteLine(count);
count++;
}

// foreach
int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
```

1.6 方法(函数)

方法是执行特定任务的代码块。

```csharp
// 定义一个方法
int Add(int x, int y)
{
return x + y;
}

// 调用方法
int result = Add(5, 3); // result = 8
```

  • 参数传递:

    • 值传递 (by value): 将参数的副本传递给方法,方法内对参数的修改不会影响原始变量。
    • 引用传递 (by reference): 使用 ref 关键字,将参数的内存地址传递给方法,方法内对参数的修改会影响原始变量。
    • 输出传递 (by output): 使用 out 关键字, 方法必须对该参数赋值, 调用前可以不初始化.
  • 方法重载: 同一个类中可以有多个同名方法,但参数列表必须不同(参数类型、数量或顺序)。

  • 可选参数: 使用 = 为参数提供默认值.

  • 命名参数: 调用方法时可以指定参数名称.

```csharp
void MyMethod(int a, int b = 10, string c = "hello") { ... }

MyMethod(5); // a=5, b=10, c="hello"
MyMethod(5, 20); // a=5, b=20, c="hello"
MyMethod(5, c: "world"); // a=5, b=10, c="world"

```

二、C# 面向对象编程 (OOP)

C# 是一种面向对象的语言,支持 OOP 的四大原则:封装、继承、多态和抽象。

2.1 类和对象

  • 类 (Class): 类是对象的蓝图,定义了对象的属性(数据)和方法(行为)。
  • 对象 (Object): 对象是类的实例。

```csharp
// 定义一个 Person 类
class Person
{
// 属性
public string Name;
public int Age;

// 方法
public void SayHello()
{
    Console.WriteLine("Hello, my name is " + Name + " and I am " + Age + " years old.");
}

}

// 创建 Person 对象
Person person1 = new Person();
person1.Name = "Alice";
person1.Age = 25;
person1.SayHello();

Person person2 = new Person { Name = "Bob", Age = 30 };
person2.SayHello();
```

2.2 构造函数

构造函数是特殊的类方法,用于创建和初始化对象。

  • 构造函数与类同名,没有返回类型。
  • 可以有多个构造函数(构造函数重载)。
  • 如果没有定义构造函数,编译器会自动提供一个默认的无参构造函数。

```csharp
class Person
{
public string Name;
public int Age;

// 构造函数
public Person(string name, int age)
{
    Name = name;
    Age = age;
}

 // 无参构造函数
public Person()
{
    Name = "Unknown";
    Age = 0;
}

}

Person person1 = new Person("Alice", 25);
Person person2 = new Person(); // 使用无参构造函数
```

2.3 封装 (Encapsulation)

封装是将数据和方法组合到一个类中,并控制对数据的访问。

  • 访问修饰符:
    • public: 任何地方都可以访问。
    • private: 只能在类内部访问。
    • protected: 只能在类内部和派生类中访问。
    • internal: 只能在同一个程序集中访问。
    • protected internal: protectedinternal 的组合.
  • 属性 (Properties): 属性提供了一种更灵活、更安全的方式来访问和修改字段的值。属性通常包含 getset 访问器。

```csharp
class Person
{
private string name; // 私有字段
private int age;

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

 public int Age
{
    get { return age; }
    set
    {
        if (value >= 0)
        {
            age = value;
        }
        else
        {
            Console.WriteLine("Age cannot be negative.");
        }
    }
}

}
```

2.4 继承 (Inheritance)

继承允许一个类(派生类)从另一个类(基类)继承属性和方法。

  • 使用 : 符号表示继承关系。
  • 派生类可以添加新的属性和方法,也可以重写基类的方法。
  • C# 不支持多重继承(一个类只能继承一个基类),但支持多接口实现。

```csharp
// 基类
class Animal
{
public string Name { get; set; }

public virtual void MakeSound() // 虚方法,允许派生类重写
{
    Console.WriteLine("Generic animal sound");
}

}

// 派生类
class Dog : Animal
{
// 重写基类的方法
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}

class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("Meow!");
}
}

Animal animal = new Animal();
animal.MakeSound(); // Generic animal sound

Dog dog = new Dog();
dog.MakeSound(); // Woof!

Cat cat = new Cat();
cat.MakeSound(); // Meow!
```

2.5 多态 (Polymorphism)

多态是指不同对象对同一消息(方法调用)做出不同响应的能力。

  • 方法重写 (override): 派生类重写基类的虚方法 (virtual) 或抽象方法 (abstract)。
  • 抽象类 (abstract class): 抽象类不能被实例化,只能被继承。抽象类可以包含抽象方法(没有实现的方法),派生类必须实现这些抽象方法。
  • 接口 (interface): 接口定义了一组方法、属性、事件和索引器,但不提供实现。类可以实现多个接口。

```csharp
// 抽象类
abstract class Shape
{
public abstract double Area(); // 抽象方法
}

// 派生类
class Circle : Shape
{
public double Radius { get; set; }

public override double Area()
{
    return Math.PI * Radius * Radius;
}

}

class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area()
{
return Width * Height;
}
}

// 接口
interface IDrawable
{
void Draw();
}

// 类实现接口
class Circle : Shape, IDrawable
{
// ... 省略其他代码
public void Draw()
{
Console.WriteLine("Drawing a circle");
}
}

// 多态
Shape shape1 = new Circle { Radius = 5 };
Shape shape2 = new Rectangle { Width = 4, Height = 6 };

Console.WriteLine(shape1.Area()); // 调用 Circle 的 Area 方法
Console.WriteLine(shape2.Area()); // 调用 Rectangle 的 Area 方法

IDrawable drawable = new Circle {Radius = 3};
drawable.Draw(); // Drawing a circle
```

三、C# 高级特性

3.1 泛型 (Generics)

泛型允许编写可以处理多种数据类型的代码,而无需为每种类型编写单独的代码。

```csharp
// 泛型类
class MyList
{
private T[] items;

public MyList(int capacity)
{
    items = new T[capacity];
}

public void Add(T item)
{
    // ... 添加元素到数组
}

public T Get(int index)
{
    return items[index];
}

}

// 使用泛型类
MyList intList = new MyList(10);
intList.Add(5);
int num = intList.Get(0);

MyList stringList = new MyList(5);
stringList.Add("Hello");
string str = stringList.Get(0);
```

3.2 委托 (Delegates) 和事件 (Events)

  • 委托 (Delegate): 委托是类型安全的函数指针,可以引用具有相同签名的方法。
  • 事件 (Event): 事件是基于委托的,用于在对象状态发生变化时通知其他对象。

```csharp
// 定义委托
delegate void MyDelegate(string message);

class Publisher
{
// 定义事件
public event MyDelegate MyEvent;

public void DoSomething()
{
    // ... 执行一些操作
    if (MyEvent != null)
    {
        MyEvent("Something happened!"); // 触发事件
    }
}

}

class Subscriber
{
public void HandleEvent(string message)
{
Console.WriteLine("Received message: " + message);
}
}

// 使用委托和事件
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();

// 订阅事件
publisher.MyEvent += subscriber.HandleEvent;
//可以取消订阅
//publisher.MyEvent -= subscriber.HandleEvent;
publisher.DoSomething(); // Received message: Something happened!
```

3.3 Lambda 表达式

Lambda 表达式是一种简洁的匿名函数,常用于委托和 LINQ 查询。

```csharp
// Lambda 表达式作为委托
MyDelegate myDelegate = (message) => { Console.WriteLine(message); };
myDelegate("Hello from Lambda!");

// Lambda 表达式用于 LINQ 查询
int[] numbers = { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0); // 筛选偶数
foreach (int num in evenNumbers)
{
Console.WriteLine(num); // 2, 4
}
```

3.4 LINQ (Language Integrated Query)

LINQ 是一种强大的查询语言,可以用于查询各种数据源,如集合、数组、数据库、XML 等。

```csharp
// LINQ 查询
List numbers = new List { 1, 2, 3, 4, 5 };

// 查询语法
var query = from n in numbers
where n > 2
orderby n descending
select n;

// 方法语法
var query2 = numbers.Where(n => n > 2).OrderByDescending(n => n);

foreach (int num in query)
{
Console.WriteLine(num); // 5, 4, 3
}
```

3.5 异步编程 (async/await)

asyncawait 关键字用于编写异步代码,可以提高应用程序的响应能力,特别是在处理 I/O 密集型操作时。

```csharp
async Task DownloadStringAsync(string url)
{
using (var client = new HttpClient())
{
// 异步下载字符串
string result = await client.GetStringAsync(url);
return result;
}
}

// 调用异步方法
async Task MyMethod()
{
string content = await DownloadStringAsync("https://www.example.com");
Console.WriteLine(content.Substring(0, 100)); // 显示前 100 个字符
}

//在Main方法中调用 (C# 7.1及以上)
static async Task Main(string[] args)
{
await MyMethod();
}

```

3.6 特性 (Attributes)

特性是添加到代码元素(如类、方法、属性等)的元数据。可以用于指示编译器或运行时执行某些操作。

```C#
[Serializable] //指示该类可以被序列化
class MyClass
{
[Obsolete("This method is deprecated. Use NewMethod instead.")] //指示方法已过时
public void OldMethod() { ... }

public void NewMethod() { ... }

}
```

四、C# 应用领域

C# 是一种用途广泛的编程语言,可用于开发各种类型的应用程序:

  • 桌面应用程序: Windows Forms, WPF (Windows Presentation Foundation)
  • Web 应用程序: ASP.NET Core (MVC, Razor Pages, Web API), Blazor
  • 移动应用程序: Xamarin (跨平台), .NET MAUI (.NET Multi-platform App UI)
  • 游戏开发: Unity (游戏引擎)
  • 云服务: Azure Functions, Azure App Service
  • 物联网 (IoT) 应用: .NET IoT Libraries
  • 机器学习: ML.NET
  • 命令行工具

五、总结

C# 是一种功能强大、易于学习且应用广泛的编程语言。本教程详细介绍了 C# 的语法、面向对象编程、高级特性以及各种应用领域。掌握 C# 将为您打开通往软件开发世界的大门,让您能够构建各种类型的应用程序。

这只是一个开始,C# 还有很多高级主题和库等待您去探索,例如:反射、表达式树、并行编程、动态编程、COM 互操作等。希望本教程能为您提供坚实的 C# 基础,并激发您继续学习和探索的兴趣。 持续练习、阅读文档和参与开源项目是提高 C# 技能的最佳途径。

THE END