news 2026/1/8 19:56:47

C#静态成员总结 常量与只读字段总结 类的继承总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#静态成员总结 常量与只读字段总结 类的继承总结

📝C# 静态成员总结

🎯核心区别表格

特性静态成员/方法非静态成员/方法
关键字static无关键字
属于谁属于类本身属于类的实例对象
调用方式类名.成员名对象.成员名
内存位置内存中只有一份每个对象都有独立副本
何时创建类加载时(程序启动)对象实例化时(new时)
生命周期程序运行期间对象存在期间

💻代码要点总结

1. 访问规则

csharp

public class People { public string Name; // 非静态字段 public static int Count; // 静态字段 // ✅ 非静态方法可以访问:静态+非静态 public void Test1() { Console.WriteLine(this.Name); // ✅ 访问非静态 Console.WriteLine(Count); // ✅ 访问静态 } // ✅ 静态方法只能访问:静态 public static void Test2() { // Console.WriteLine(Name); // ❌ 错误!不能访问非静态 Console.WriteLine(Count); // ✅ 只能访问静态 } }

2. 使用场景对比

csharp

// 使用示例 People p1 = new People(); p1.Name = "张三"; // ✅ 对象访问非静态成员 People.Count = 20; // ✅ 类名访问静态成员 p1.Test1(); // ✅ 对象调用非静态方法 People.Test2(); // ✅ 类名调用静态方法

🎮游戏开发实用示例

示例1:玩家计数器

csharp

public class 玩家 { public string 名字; // 非静态:每个玩家不同 public static int 总玩家数; // 静态:所有玩家共享 public 玩家(string 名称) { 名字 = 名称; 总玩家数++; // 静态计数器,统计总数 } public void 显示信息() { // 非静态方法可以访问静态成员 Console.WriteLine($"玩家:{名字},总玩家数:{总玩家数}"); } } // 使用 玩家 玩家1 = new 玩家("张三"); 玩家 玩家2 = new 玩家("李四"); 玩家1.显示信息(); // 输出:玩家:张三,总玩家数:2

示例2:游戏工具类

csharp

// 静态工具类 - 不需要实例化 public static class 游戏工具 { public static int 生成随机数(int 最小值, int 最大值) { Random rnd = new Random(); return rnd.Next(最小值, 最大值); } public static float 计算伤害(float 攻击力, float 防御力) { return 攻击力 * 100 / (100 + 防御力); } } // 使用:直接通过类名调用 int 随机伤害 = 游戏工具.生成随机数(10, 50); float 最终伤害 = 游戏工具.计算伤害(100, 30);

🔑关键记忆点

1. this 关键字

  • 只在非静态方法中使用

  • 代表当前对象实例

  • 可以省略(编译器自动推断)

csharp

public void Test() { Console.WriteLine(this.Name); // 显式使用this Console.WriteLine(Name); // 隐式使用this(效果相同) }

2. 静态构造器

csharp

public class 配置管理器 { public static string 游戏版本; // 静态构造器:类加载时自动执行一次 static 配置管理器() { 游戏版本 = "v1.0.0"; Console.WriteLine("静态构造器执行"); } }

3. 实用场景总结

csharp

// ✅ 使用静态: // 1. 工具类方法(Math.Max, Console.WriteLine) // 2. 全局配置(游戏设置、数据库连接字符串) // 3. 计数器、统计信息 // 4. 工厂方法 // ✅ 使用非静态: // 1. 对象特有属性(玩家名字、血量) // 2. 需要操作对象状态的方法 // 3. 需要继承和多态的场景

⚠️常见错误

错误1:静态访问非静态

csharp

public static void 静态方法() { Console.WriteLine(Name); // ❌ 错误!静态方法不能访问非静态字段 }

错误2:混淆调用方式

csharp

People p = new People(); p.Count = 10; // ⚠️ 不推荐!虽然能编译,但让人困惑 People.Count = 10; // ✅ 正确!明确表示操作静态成员

💡快速判断指南

问自己几个问题:

  1. 这个数据/方法需要每个对象独立吗?

    • 是 → 用非静态

    • 否 → 考虑静态

  2. 这个方法需要操作对象内部状态吗?

    • 是 → 用非静态

    • 否 → 考虑静态

  3. 这个方法像工具函数吗?(如计算、转换)

    • 是 → 用静态

📚一句话总结

静态属于类,一份共享;非静态属于对象,各自独立。静态不能直接访问非静态,但非静态可以访问静态。

记住这个核心规则,就能正确使用静态和非静态成员了!

📝C# 常量(const)与只读字段(readonly)总结

🎯核心区别表格

特性常量(const)只读字段(readonly)
关键字constreadonly
赋值时机编译时(声明时必须赋值)运行时(可在声明时或构造函数中赋值)
内存位置编译时直接替换(类似宏)存储在类型的内存中
类型限制只能是基本类型(int, string等)可以是任何类型
静态性隐式静态可静态或实例
性能更好(编译时优化)正常访问
修改灵活性重新编译才能修改可在构造函数中设置不同值

💻代码要点详解

1. 基本语法对比

csharp

class 游戏配置 { // ✅ 常量 - 编译时确定 public const double 默认税率 = 0.1; public const string 游戏名称 = "三角洲行动"; // ✅ 只读字段 - 运行时确定 public readonly DateTime 创建时间; public readonly List<string> 武器列表; public static readonly int 服务器ID; }

2. 赋值规则总结

csharp

class 三角洲 { // ✅ 只读字段可以在声明时赋值 public readonly double 资产 = 10000; public static readonly string 昵称 = "伊娃诺夫斯基"; // ✅ 也可以在构造函数中赋值 public 三角洲() { 资产 = 10000000; // ✅ 非静态只读字段可以在构造中修改 // 昵称 = "ss"; // ❌ 静态只读字段不能在非静态构造中修改 } // ✅ 静态只读字段只能在静态构造中修改 static 三角洲() { 昵称 = "ss"; // ✅ 可以在静态构造中修改 } public void 普通方法() { // 资产 = 100; // ❌ 只读字段不能在普通方法中修改 } }

🎮游戏开发实用示例

示例1:配置系统

csharp

public class 游戏设置 { // ✅ 真正的常量 - 永远不会变 public const string 游戏引擎 = "Unity"; public const int 最大帧率 = 144; // ✅ 只读配置 - 启动时确定,运行时不变 public readonly string 语言设置; public readonly bool 开启音效; public static readonly DateTime 游戏启动时间; // 静态构造器初始化静态只读字段 static 游戏设置() { 游戏启动时间 = DateTime.Now; } // 实例构造器初始化实例只读字段 public 游戏设置(string 语言, bool 音效) { 语言设置 = 语言; 开启音效 = 音效; } }

示例2:装备属性

csharp

public class 装备 { // ✅ 常量:所有装备共享的固定值 public const int 最大耐久度 = 100; public const string 装备品质_传说 = "Legendary"; // ✅ 只读:每个装备特有的属性 public readonly string 装备名称; public readonly int 基础攻击力; public readonly DateTime 获取时间; public 装备(string 名称, int 攻击力) { 装备名称 = 名称; 基础攻击力 = 攻击力; 获取时间 = DateTime.Now; // 每个装备获取时间不同 } }

🔑关键规则总结

1. 只读字段的修改权限

csharp

class 示例 { // 实例只读字段: // ✅ 声明时赋值 // ✅ 实例构造函数中赋值 // ❌ 其他方法中赋值 // ❌ 静态方法中赋值 // 静态只读字段: // ✅ 声明时赋值 // ✅ 静态构造函数中赋值 // ❌ 实例构造函数中赋值 // ❌ 其他方法中赋值 }

2. 常量与只读的编译行为

csharp

const int MAX_LEVEL = 100; readonly int CurrentLevel = 1; // 编译后: // MAX_LEVEL 被直接替换为字面值 100 // CurrentLevel 仍然是字段访问

3. 重要注意事项

csharp

public class 玩家 { // ❌ 常量不能用自定义类型 // public const List<string> 技能列表 = new List<string>(); // ✅ 只读字段可以用任何类型 public readonly List<string> 技能列表 = new List<string>(); // 注意:只读只保护引用,不保护对象内容! public void 学习技能() { // 技能列表 = new List<string>(); // ❌ 不能重新赋值 技能列表.Add("火球术"); // ✅ 可以修改列表内容 } }

💡使用场景选择指南

✅ 使用 const 的情况:

csharp

// 1. 数学/物理常数 public const double PI = 3.1415926535; public const float 重力加速度 = 9.8f; // 2. 固定配置值 public const int 最大玩家数 = 100; public const string 默认语言 = "zh-CN"; // 3. 枚举值的替代(简单情况) public const int 状态_空闲 = 0; public const int 状态_战斗中 = 1;

✅ 使用 readonly 的情况:

csharp

// 1. 需要运行时确定的配置 public readonly string 数据库连接字符串; public readonly int 服务器端口; // 2. 对象特有但创建后不变的属性 public readonly DateTime 出生日期; public readonly string 角色ID; // 3. 复杂类型的不变引用 public readonly Dictionary<string, int> 物品价格表; public readonly Color 主题颜色;

⚠️常见错误与陷阱

错误1:混淆赋值时机

csharp

class 测试 { public readonly int 数值; public 测试(int x) { // 这里可以赋值 数值 = x; } public void 修改() { // 这里不能赋值! // 数值 = 10; // ❌ 编译错误 } }

错误2:静态只读字段的错误使用

csharp

class 游戏 { public static readonly int 玩家数量; public 游戏() { // 玩家数量 = 1; // ❌ 错误!静态只读不能在实例构造中赋值 } static 游戏() { 玩家数量 = 0; // ✅ 正确!在静态构造中赋值 } }

陷阱:只读字段的对象内容可变

csharp

public class 背包 { public readonly List<string> 物品列表 = new List<string>(); public void 添加物品(string 物品) { 物品列表.Add(物品); // ✅ 可以!只读的是引用,不是内容 // 物品列表 = new List<string>(); // ❌ 不可以!不能重新赋值 } }

🚀最佳实践建议

1. 明确意图

csharp

// 明确表达:"这个值永远不会变" public const double 数学常数_PI = 3.14159; // 明确表达:"这个值对象创建后不会变" public readonly DateTime 账号创建时间; // 明确表达:"这个值类加载后不会变" public static readonly string 游戏版本号;

2. 命名约定

csharp

// 常量:全部大写,下划线分隔 public const int MAX_PLAYER_COUNT = 100; public const string DEFAULT_LANGUAGE = "zh-CN"; // 只读字段:正常Pascal命名 public readonly DateTime AccountCreateTime; public static readonly string GameVersion;

3. 性能考虑

csharp

// 频繁访问的固定值用const(编译时优化) public const int BUFFER_SIZE = 1024; // 需要运行时计算的用readonly public readonly int CacheSize = CalculateOptimalCacheSize();

📚一句话总结

const是"编译时就固定"的永恒不变,readonly是"运行时确定但之后不变"的承诺。

记住:

  • const→ 简单类型,真正永恒不变,编译时替换

  • readonly→ 任何类型,对象/类创建后不变,运行时确定

选择时问自己:"这个值在编译时就能确定吗?"

  • 能 → 考虑const

  • 不能 → 用readonly

📝C# 类的继承与构造函数总结

🎯继承的核心概念

📚面向对象四大特征总结

特征说明示例
封装隐藏内部实现,暴露必要接口属性封装字段,方法封装逻辑
继承子类获得父类特性,避免重复代码class Student : People
多态同一接口不同实现,提高灵活性虚方法重写、接口实现
抽象定义规范而不指定实现抽象类、接口

1. 继承的基本语法

csharp

// 父类(基类) class People { public string Name { get; set; } public int Age { get; set; } } // 子类(派生类)使用 : 继承 class Student : People { public int StudentId { get; set; } }

2. 继承的访问权限

csharp

class People { public string Name; // ✅ 公共 - 可以被继承和访问 private string Secret; // ❌ 私有 - 不能被继承 protected string Nickname; // ✅ 受保护 - 可以被继承,但不能被外部对象访问 protected internal string Code; // ✅ 可以被继承,可以在同一程序集访问 } class Student : People { public void Show() { Console.WriteLine(Name); // ✅ 可以访问 // Console.WriteLine(Secret); // ❌ 不能访问私有 Console.WriteLine(Nickname); // ✅ 可以访问受保护 Console.WriteLine(Code); // ✅ 可以访问 } }

🔄构造函数的执行顺序

1. 默认执行顺序

csharp

class People { public People() { Console.WriteLine("父类构造执行"); } } class Student : People { public Student() { Console.WriteLine("子类构造执行"); } } // 使用 Student s = new Student(); // 输出: // 父类构造执行 // 子类构造执行

2. 手动调用父类有参构造

csharp

class People { public string Name; public int Age; public People() { } public People(string name, int age) { Name = name; Age = age; Console.WriteLine($"父类有参构造: {name}, {age}"); } } class Student : People { public int Score; // 调用父类有参构造 public Student(string name, int age, int score) : base(name, age) // 🔑 关键在这里! { Score = score; Console.WriteLine($"子类构造,分数: {score}"); } } // 使用 Student s = new Student("张三", 18, 90); // 输出: // 父类有参构造: 张三, 18 // 子类构造,分数: 90

📊继承规则总结表

特性能否被继承说明
公共成员(public)✅ 可以子类和外部都可访问
私有成员(private)❌ 不能仅本类可访问
受保护成员(protected)✅ 可以子类可访问,外部不可
内部成员(internal)✅ 可以(同程序集)同一程序集内可访问
受保护内部(protected internal)✅ 可以子类或同程序集
方法✅ 可以遵循访问修饰符规则
构造函数❌ 不能但会隐式/显式调用
静态成员✅ 可以但属于父类,不重复创建

🎮游戏开发继承示例

示例1:游戏角色继承体系

csharp

// 基类:所有游戏角色的共性 public class GameCharacter { public string Name { get; set; } public int Level { get; set; } public int Health { get; set; } public GameCharacter(string name) { Name = name; Level = 1; Health = 100; } public virtual void Attack() { Console.WriteLine($"{Name}发起普通攻击"); } } // 战士类 public class Warrior : GameCharacter { public int Armor { get; set; } public Warrior(string name, int armor) : base(name) // 调用父类构造 { Armor = armor; } public override void Attack() { Console.WriteLine($"{Name}使用剑猛砍!"); } public void Defend() { Console.WriteLine($"{Name}举盾防御"); } } // 法师类 public class Mage : GameCharacter { public int Mana { get; set; } public Mage(string name, int mana) : base(name) { Mana = mana; } public override void Attack() { Console.WriteLine($"{Name}释放火球术!"); } public void CastSpell() { Console.WriteLine($"{Name}施法消耗{10}法力"); Mana -= 10; } }

示例2:多层继承

csharp

// 基类 public class Vehicle { public string Brand { get; set; } public Vehicle(string brand) { Brand = brand; } } // 一级派生 public class Car : Vehicle { public int Doors { get; set; } public Car(string brand, int doors) : base(brand) { Doors = doors; } } // 二级派生 public class SportsCar : Car { public int MaxSpeed { get; set; } public SportsCar(string brand, int doors, int maxSpeed) : base(brand, doors) // 调用直接父类构造 { MaxSpeed = maxSpeed; } }

⚠️重要注意事项

1. 单继承限制

csharp

// ❌ 错误:C#不支持多继承 // class MyClass : ClassA, ClassB // 编译错误 // ✅ 正确:但可以实现多个接口 class MyClass : ClassA, IInterface1, IInterface2 // ✅ 正确:支持多层继承 class GrandParent { } class Parent : GrandParent { } class Child : Parent { } // 包含 GrandParent 和 Parent 的成员

2. 构造函数调用规则

csharp

class Parent { public Parent() { } // 无参构造 public Parent(int x) { } // 有参构造 } class Child : Parent { // 如果不写 : base(),编译器会自动调用父类无参构造 public Child() { } // 如果父类没有无参构造,子类必须显式调用有参构造 public Child(int x) : base(x) { } }

3. 继承链中的访问权限

csharp

class A { protected int Value = 10; } class B : A { public void Show() { Console.WriteLine(Value); // ✅ 可以访问 } } class C : B { public void Display() { Console.WriteLine(Value); // ✅ 可以访问(通过B继承) } }

💡最佳实践

1. 合理的继承层次

csharp

// ✅ 好的设计:"是一个"的关系 class Animal { } class Dog : Animal { } // 狗是一种动物 class Cat : Animal { } // 猫是一种动物 // ❌ 不好的设计:"有一个"的关系 class Car { } class Engine { } // class Car : Engine { } // 错误!车有引擎,但不是引擎

2. 使用 base 关键字

csharp

class Parent { protected string message = "来自父类"; public virtual void Show() { Console.WriteLine(message); } } class Child : Parent { public override void Show() { base.Show(); // 调用父类方法 Console.WriteLine("添加子类功能"); } }

3. 构造函数的设计

csharp

// 推荐:为基类提供无参构造,便于继承 public class BaseClass { public BaseClass() { } public BaseClass(string param) { } } // 或者在派生类中显式调用基类构造 public class DerivedClass : BaseClass { public DerivedClass() : base("默认值") { } }


🚀一句话总结

继承让代码复用,构造函数执行顺序:先父后子,用: base()调用父类构造。

记住:

  • 继承关系是"是什么"(is-a)的关系

  • 构造函数总是从最基类开始执行

  • 访问权限决定哪些成员可以被子类使用

  • 单继承,多接口是C#的设计原则

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/5 22:44:58

东莞有专业“图生视频”企业?背后奥秘待揭秘

在东莞的内容创作领域&#xff0c;传统视频制作面临成本高、耗时长等困境。某行业实践验证&#xff0c;传统创作成本比新兴方式高出百倍以上。本文将深入剖析“图生视频”背后的奥秘。现状与挑战传统视频创作成本高昂&#xff0c;每月花费在数千元到数万元不等&#xff0c;且耗…

作者头像 李华
网站建设 2026/1/5 22:44:53

iOS 应用发布流程中常被忽视的关键环节

在很多项目里&#xff0c;“发布 iOS 应用”经常被视为开发结束后的自然延伸。但当你真正负责一次完整发布时&#xff0c;很快会意识到&#xff0c;这并不是一个单点操作&#xff0c;而是一段横跨多个工具、多个系统、多个角色的工程过程。 我第一次完整跑完 iOS 发布全流程时&…

作者头像 李华
网站建设 2026/1/5 22:44:51

什么是云桌面?一般都用哪些云桌面?

随着数字化时代的快速发展&#xff0c;云计算技术逐渐渗透到各行各业&#xff0c;其中云桌面作为一种创新的工作与学习方式&#xff0c;正受到广泛关注。它不仅提升了资源利用效率&#xff0c;还增强了数据安全性和访问灵活性。特别是在教育领域&#xff0c;结合人工智能技术的…

作者头像 李华