C#语法查缺补漏

C#语法补充

空条件运算符和空合并运算符

  • var clientIp = context.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
- 首先RemoteIpAddress允许为空
- 若这个表达式(context.HttpContext.Connection.RemoteIpAddress?.ToString())值为null,则返回右边的值
  • 类似的语法模式如下
// 示例1:处理可能为null的配置值
var connectionString = Configuration.GetSection("ConnectionStrings:Default")?.Value ?? "DefaultConnection";

// 示例2:处理可能为null的用户输入
var userName = user?.Name ?? "匿名用户";

// 示例3:处理可能为null的集合
var firstItem = items?.FirstOrDefault() ?? defaultItem;

值类型引用类型的区别

值类型 (Value Types)

特点:

  • 直接存储数据本身
  • 分配在栈(stack)上(但作为类成员时随对象在堆上)
  • 赋值时复制整个值
  • 不能为null(除非使用可空类型)

主要分类:

// 1. 基本数值类型
int number = 10;
double price = 99.99;
bool flag = true;
char character = 'A';

// 2. 结构体 (struct)
struct Point
{
    public int X;
    public int Y;
}

// 3. 枚举 (enum)
enum Color { Red, Green, Blue }

引用类型 (Reference Types)

特点:

  • 存储的是内存地址引用
  • 分配在堆(heap)上
  • 赋值时复制引用,而不是数据本身
  • 可以为null

主要分类:

// 1. 类 (class)
class Person
{
    public string Name;
    public int Age;
}

// 2. 接口 (interface)
interface IAnimal
{
    void Speak();
}

// 3. 数组
int[] numbers = new int[5];
string[] names = new string[3];

// 4. 委托 (delegate)
delegate void MyDelegate(string message);

// 5. 字符串
string text = "Hello World";

核心区别

1. 内存分配和存储

// 值类型示例
int a = 10;
int b = a;  // 复制值
b = 20;     // 不影响a
Console.WriteLine(a); // 输出: 10

// 引用类型示例
Person p1 = new Person { Name = "John" };
Person p2 = p1;       // 复制引用
p2.Name = "Jane";     // 影响p1
Console.WriteLine(p1.Name); // 输出: Jane

2. 参数传递行为

void ModifyValue(int value) => value = 100;
void ModifyReference(Person person) => person.Name = "Modified";

int num = 50;
Person person = new Person { Name = "Original" };

ModifyValue(num);      // num不变,还是50
ModifyReference(person); // person.Name变成"Modified"

3. 默认值不同

int defaultInt;        // 0
bool defaultBool;      // false
Person defaultPerson;  // null

4. 相等比较

// 值类型比较内容
int x = 5, y = 5;
Console.WriteLine(x == y); // True

// 引用类型默认比较引用
Person p1 = new Person { Name = "Tom" };
Person p2 = new Person { Name = "Tom" };
Console.WriteLine(p1 == p2); // False(除非重写==运算符)

特殊情况和注意事项

1. 装箱和拆箱 (Boxing/Unboxing)

// 装箱:值类型 → 引用类型
int value = 42;
object boxed = value;  // 装箱

// 拆箱:引用类型 → 值类型
int unboxed = (int)boxed;  // 拆箱

2. ref 关键字

void ModifyWithRef(ref int value) => value = 100;

int number = 50;
ModifyWithRef(ref number);
Console.WriteLine(number); // 输出: 100

3. 可空值类型

int? nullableInt = null;        // 等价于 Nullable<int>
DateTime? nullableDate = null;

性能考虑

  • 值类型:栈分配,快速,无GC压力
  • 引用类型:堆分配,需要GC管理,有开销

选择指南

使用值类型当:

  • 类型表示单个值
  • 实例大小较小(通常<16字节)
  • 不需要继承
  • 希望避免堆分配

使用引用类型当:

  • 类型是复杂对象
  • 需要继承和多态
  • 实例可能很大
  • 需要共享引用

理解这两种类型的区别对于编写高效、正确的C#代码至关重要,特别是在处理性能敏感场景时。

表达式体

  • 只读属性
// 传统写法
public int TemperatureF 
{ 
    get { return 32 + (int)(TemperatureC / 0.5556); } 
}

// 表达式体写法(更简洁)
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
  • 只读属性计算
public class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }
    
    // 计算面积
    public double Area => Width * Height;
    
    // 计算周长
    public double Perimeter => 2 * (Width + Height);
    
    // 判断是否为正方形
    public bool IsSquare => Width == Height;
}
  • 属性访问器
public class Student
{
    private string _name;
    
    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException(nameof(value));
    }
    
    private int _age;
    public int Age
    {
        get => _age;
        set => _age = value >= 0 ? value : throw new ArgumentException("年龄不能为负数");
    }
}
  • 方法中的表达式体
public class Calculator
{
    // 传统方法
    public int Add(int a, int b)
    {
        return a + b;
    }
    
    // 表达式体方法
    public int Add(int a, int b) => a + b;
    
    public double Divide(double x, double y) => y != 0 ? x / y : 0;
}
  • 构造函数和析构函数
public class Person
{
    public string FirstName { get; }
    public string LastName { get; }
    
    // 表达式体构造函数
    public Person(string firstName, string lastName) => 
        (FirstName, LastName) = (firstName, lastName);
    
    // 表达式体析构函数
    ~Person() => Console.WriteLine("Person对象被销毁");
}
  • 更多实例
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    
    // 计算总价
    public decimal TotalPrice => Price * Quantity;
    
    // 判断是否有库存
    public bool InStock => Quantity > 0;
    
    // 价格是否合理
    public bool IsExpensive => Price > 100;
    
    // 获取商品信息摘要
    public string Summary => $"{Name} - ¥{Price} {(InStock ? "有货" : "缺货")}";
}

public class MathHelper
{
    // 数学计算方法
    public static double CircleArea(double radius) => Math.PI * radius * radius;
    public static bool IsEven(int number) => number % 2 == 0;
    public static string NumberType(int num) => num > 0 ? "正数" : num < 0 ? "负数" : "零";
}

- 实例应用

// 创建对象并使用
var product = new Product 
{ 
    Name = "笔记本电脑", 
    Price = 5999, 
    Quantity = 5 
};

Console.WriteLine(product.Summary);        // 笔记本电脑 - ¥5999 有货
Console.WriteLine(product.TotalPrice);     // 29995
Console.WriteLine(product.IsExpensive);    // True

// 使用数学帮助类
Console.WriteLine(MathHelper.CircleArea(5));     // 78.54...
Console.WriteLine(MathHelper.IsEven(10));        // True
Console.WriteLine(MathHelper.NumberType(-5));    // 负数

C# 表达式体成员详解

作为初学者,表达式体语法确实需要一些时间来熟悉。让我通过多个例子来帮助你理解:

1. 只读属性(你代码中的用法)

// 传统写法
public int TemperatureF 
{ 
    get { return 32 + (int)(TemperatureC / 0.5556); } 
}

// 表达式体写法(更简洁)
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

2. 方法中的表达式体

public class Calculator
{
    // 传统方法
    public int Add(int a, int b)
    {
        return a + b;
    }
    
    // 表达式体方法
    public int Add(int a, int b) => a + b;
    
    public double Divide(double x, double y) => y != 0 ? x / y : 0;
}

3. 只读属性计算

public class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }
    
    // 计算面积
    public double Area => Width * Height;
    
    // 计算周长
    public double Perimeter => 2 * (Width + Height);
    
    // 判断是否为正方形
    public bool IsSquare => Width == Height;
}

4. 构造函数和析构函数

public class Person
{
    public string FirstName { get; }
    public string LastName { get; }
    
    // 表达式体构造函数
    public Person(string firstName, string lastName) => 
        (FirstName, LastName) = (firstName, lastName);
    
    // 表达式体析构函数
    ~Person() => Console.WriteLine("Person对象被销毁");
}

5. 属性访问器

public class Student
{
    private string _name;
    
    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException(nameof(value));
    }
    
    private int _age;
    public int Age
    {
        get => _age;
        set => _age = value >= 0 ? value : throw new ArgumentException("年龄不能为负数");
    }
}

6. 更多实用例子

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    
    // 计算总价
    public decimal TotalPrice => Price * Quantity;
    
    // 判断是否有库存
    public bool InStock => Quantity > 0;
    
    // 价格是否合理
    public bool IsExpensive => Price > 100;
    
    // 获取商品信息摘要
    public string Summary => $"{Name} - ¥{Price} {(InStock ? "有货" : "缺货")}";
}

public class MathHelper
{
    // 数学计算方法
    public static double CircleArea(double radius) => Math.PI * radius * radius;
    public static bool IsEven(int number) => number % 2 == 0;
    public static string NumberType(int num) => num > 0 ? "正数" : num < 0 ? "负数" : "零";
}

7. 使用示例

// 创建对象并使用
var product = new Product 
{ 
    Name = "笔记本电脑", 
    Price = 5999, 
    Quantity = 5 
};

Console.WriteLine(product.Summary);        // 笔记本电脑 - ¥5999 有货
Console.WriteLine(product.TotalPrice);     // 29995
Console.WriteLine(product.IsExpensive);    // True

// 使用数学帮助类
Console.WriteLine(MathHelper.CircleArea(5));     // 78.54...
Console.WriteLine(MathHelper.IsEven(10));        // True
Console.WriteLine(MathHelper.NumberType(-5));    // 负数

关键要点

  1. 语法成员 => 表达式

  2. 适用场景

    • 方法体只有一行返回语句
    • 只读属性
    • 简单的属性访问器
  3. 优点

    • 代码更简洁
    • 可读性更强
    • 减少大括号嵌套
  4. 限制

    • 不能包含复杂的逻辑块
    • 不能使用多个语句

记住:表达式体主要是为了让简单的单行代码更简洁,对于复杂的逻辑还是应该使用传统的大括号语法。

posted @ 2025-10-23 10:00  清安宁  阅读(11)  评论(0)    收藏  举报