当前位置: 首页 > news >正文

C#1:类、名称空间

C#1:类、名称空间

以刘铁猛老师和清华大学出版社《C#高级编程12版》进行学习。

C#程序的结构

名称空间(namespace){类(class){方法{语句、表达式;}}
}
using System;//使用名称空间
using System.Collections.Generic;
namespace IndexerExample//命名空间声明,用于组织代码
{class Program//类声明,所有代码必须包含在类中{static void Main(string[] args)//主方法(Main),程序的入口点{int x=10;Console.WriteLine(x);//语句与表达式,执行具体的输出操作}}
}

名称空间:以树型结构组织类(和其他类型)

namespace Example{ //写法一namespace ObjectExample{namespace IndexerExample{class Sample{public void CS(){Console.WriteLine("cs");}}}}
}
写法二
namespace Example.ObjectExample.IndexerExample{class Sample{public string CS(){int astring b= a+"cs";}}
}
//使用名称空间 using
using Example.ObjectExample.IndexerExample;//方法一
namespace A{class Program{static void Main(string[] args){string a = CS(1);//方法一:先调用后使用string b = using Example.ObjectExample.IndexerExample.CS(2);//方法2:使用时调用}}
}
//别名:给长的名称空间起一个小名字
using Webtimer = System.Web.UI.Timer;

类:构成程序的主体

类和名称空间

类和名称空间:类和名称空间都存储在类库中。类库引用是使用命名空间的物理基础。

例如:就像书是放在图书馆这样一个物理空间。Generic书在System图书馆的Collections中。Program在一个xx类库中,类库名字为IndexerExample。

声明

声明 Declaration:在程序中引入一个新的标识符,告诉编译器某个实体(如变量、类、方法等)的存在及其类型,但通常不一定会立即为它分配内存空间或赋予初始值。

  • 变量声明int number; (告诉编译器这里有个整型变量叫 number)
  • 方法声明:定义一个方法的名字、返回值类型和参数列表。
  • 类/结构体声明:例如 class Car { },定义了一个新的类型。
  • 命名空间声明:例如 namespace MyProject { },用于组织代码逻辑组。

声明 vs 初始化 vs 实例化

  • 声明(Declaration)

    :只生成对象或变量名,不赋值,不分配内存。

    • 代码string str;
  • 初始化(Initialization):本质都是“给变量赋予初始状态”

    :在声明的基础上,给变量或对象赋予一个初始值。

    • 代码int x = 1;
    • 底层动作:
      • 对于值类型(如 int a = 10;:初始化只是把数据 10 写入栈(Stack)上已经分配好的内存空间。
      • 对于引用类型(如 MyClass obj = new MyClass();:初始化只是把堆上对象的内存地址(指针)写入栈(Stack)上的局部变量中。
  • 实例化(Instantiation)

    :专门针对“引用类型(如类)”,使用new关键字在内存(堆)中为对象分配空间,并调用构造函数。

    • 代码A a = new A();
    • 底层动作:当你使用 new 关键字时,C# 运行时(CLR)会在内存的堆区中,根据类的结构精确地划出一块空间,用来存放这个对象的所有实例数据(成员变量)。

    在 C# 的语境下,我们通常不说“引用类型不能被初始化”,而是这样理解:

    1. 对于值类型(如 int:初始化是直接把具体的数据(如 10)拷贝到栈上的内存空间里。
    2. 对于引用类型(如 stringclass:初始化是把对象的内存地址拷贝到栈上的变量里。

    实例化必须带上new关键字(没有的说明C#进行了隐藏),引用数据类型必定实例化:string的编译器封装了实例化 + 初始化。

    [!IMPORTANT]

    “实例化” = 在堆上造房子(分配内存);“初始化” = 在栈上给门牌号(赋值/存地址)。

    int [] myArray = new int []{1,2,3,4};
    int[]myArray //声明 底层真相:这一步仅是在内存的“栈(Stack)”上创建了一个名为 myArray 的变量
    myArray = new int []//实例化 底层真相:new 关键字触发了实例化。此时,C# 运行时会在内存的“堆(Heap)”上真正开辟一块连续的空间,用来存放n个int 类型的数据。同时,它会将这块内存的地址返回,赋给栈上的 myArray 变量。
    {1,2,3,4}//初始化 语法糖 把 1、2、3、4 赋值给刚才在堆上创建好的那 4 个 int 空间,覆盖掉原本的 0。
    

声明与定义

声明只是提供名称和类型,而定义(Definition)则是在声明的基础上,为标识符分配内存并提供初始值或具体实现。

  • 变量示例int number; 是声明;number = 10; 是定义(赋值)。
  • 方法示例void MyMethod(); 是声明(只告诉编译器有这个方法);而包含具体代码块 { ... } 的则是方法的定义。
概念 核心动作 发生时机 本质
声明 (Declaration) 告诉编译器“有这个东西” 编译时 占位,不分配内存
定义 (Definition) 真正“创造”这个东西 编译时 分配内存 / 生成代码
初始化 (Initialization) 给变量/对象赋予初始值 编译时/运行时 赋值,不一定分配内存
实例化 (Instantiation) 用类在内存中创建对象 运行时 在堆上分配内存,创建对象

初解: 类(class):现实世界事物的模型

  • 类是对现实世界事物抽象的结果(建模)。

    • 事物包括“物质”(实体)与“运动”(逻辑)。
    • 建模是一个去伪存真,由表及里的过程。

    目标:学习类的三大成员,两大状态,类与对象的关系

类的三大成员,两大状态

静态状态(Static Members) 实例状态(Instance Members )
字段:(Field)
常量:(Constant)
属性:(property)
索引器(Indexer)
方法:(Method)
事件:(Event)
运算符重载(Operator)
构造函数(Constructor)
终结器/析构函数(Finalizer)
嵌套类型(Nested Type)
using System;
public class Person
{// ================= 1. 数据成员(状态/数据) =================// 字段(Field):私有状态,通常用于内部存储private string _name; 
// 常量(Constant):编译时确定的固定值
public const string Species = "Homo Sapiens"; // 属性(Property):公有状态,通过 get/set 访问器控制数据的读写
public int Age { get; set; } // 索引器(Indexer):允许对象像数组一样被索引
private string[] _nicknames = new string[3];
public string this[int index]
{get => _nicknames[index];set => _nicknames[index] = value;
}// ================= 2. 函数成员(行为/操作) =================
// 方法(Method):定义对象可以执行的操作
public void Introduce()
{Console.WriteLine($"我是 {_name},今年 {Age} 岁。");
}// 事件(Event):用于向外部发送通知(观察者模式的基础)
public event Action OnBirthday; // 运算符重载(Operator):自定义预定义运算符的行为
public static Person operator +(Person p1, Person p2)
{return new Person { _name = $"{p1._name} & {p2._name}" };
}// ================= 3. 生命周期与嵌套成员 =================
// 构造函数(Constructor):实例化时调用,负责初始化对象状态
public Person(string name, int age)
{_name = name;Age = age;
}// 终结器/析构函数(Finalizer):GC 回收对象前调用,用于清理非托管资源
~Person()
{Console.WriteLine($"{_name} 正在被垃圾回收器销毁...");
}// 嵌套类型(Nested Type):定义在类内部的类,仅服务于外部类
public class Address
{public string City { get; set; }
}// ================= 4. 两大状态(静态 vs 实例) =================
// 静态成员(Static):属于类本身,所有实例共享,存在静态存储区
public static int TotalPopulation { get; set; } = 0;
}

两大状态维度(静态 vs 实例)

上述所有成员,都可以根据其归属划分为两种截然不同的状态:

  • 实例状态(Instance Members)
    • 归属:属于具体的“对象(实例)”。
    • 内存特征:每次使用 new 实例化时,都会在堆(Heap)上分配独立的内存空间。每个对象的实例成员互不影响。
    • 访问方式:必须通过具体的对象引用来访问(如 person.Age)。
  • 静态状态(Static Members)
    • 归属:属于“类本身”,而非任何具体的对象。
    • 内存特征:在类加载时分配,存在于静态存储区,全局只有一份副本,被所有实例共享。
    • 访问方式:直接通过“类名.成员名”访问(如 Person.TotalPopulation),无需实例化。

类(Class)与对象(Object)的关系

  1. 对象也叫实例,是类经过”实例化”后得到的内存中的实体
    • Formally"instance” is synonymous with“object”-对象和实例是一回事
    • "飞机"与”一架飞机”有何区别?天上有(一架)飞机一一必需是实例飞,概念是不能飞的
    • 有些类是不能实例化的,比如”数学”(Mathclass),我们不能说”一个数学”
  2. 依照类,我们可以创建对象,这就是“实例化”
    • 现实世界中常称“对象”,程序世界中常称“实例”
    • 二者并无太大区别,常常混用,初学者不必迷惑
  3. 使用new操作符创建类的实例
  4. 引用变量与实例的关系
    • 孩子与气球
    • 气球不一定有孩子牵着
    • 多个孩子可以使用各自的绳子牵着同一个气球,也可以都通过一根绳子牵着气球

理解:类定义了内存的分配法则(结构蓝图),对象是在堆中“按照”这个法则开辟独立的物理空间完成实例化,并将堆上的“内存地址”赋值给栈中的引用变量。

**1. 类定义了某种内存的分配法则 **

类(Class)在编译后,会生成一份“元数据(Metadata)”,存放在内存的方法区(Metaspace)中。这份元数据就像是一张极其精确的“建筑图纸”,它规定了:

  • 这个对象需要多少内存空间(比如一个 int 占 4 字节,一个 string 引用占 8 字节)。
  • 字段的排列顺序。
  • 包含哪些方法(方法代码只存一份,供所有对象共享)。

所以,类确实定义了内存的分配法则和结构。

2. 对象是在堆中按照类的内存分配法则 **
对象在堆中
“遵循/按照”**这个法则,在堆(Heap)上实打实地划出一块连续的物理空间。

  • 图纸与房子的区别:就像盖房子,施工队(JVM/C# 运行时)是看着图纸(类元数据)去堆里圈地、盖房子(分配内存)。
  • 独立的数据副本:堆里分配出来的这块空间,只存放该对象独有的“实例数据(Instance Data)”。同类型的 100 个对象,会在堆上开辟 100 块独立的内存,但它们都“指向”同一份类元数据。

**3. 并将对应的内存地址“赋值”到声明的栈中 **

  • 当你写下 MyClass obj; 时,编译器已经在栈上为 obj 分配了空间(比如 8 字节的指针大小),这属于定义/声明
  • 当执行 obj = new MyClass(); 时,堆上的房子盖好了,返回了一个堆内存地址(比如 0x1A2B)。此时,把这个地址写入栈上 obj 变量的过程,在底层本质上是一个赋值(Assignment)动作。
  • 虽然在宏观语法上我们常说“用 new 来初始化一个对象”,但在严谨的底层逻辑中,这是将堆地址赋给栈变量的过程。

[!IMPORTANT]

  1. 类加载时:编译器把类的结构蓝图(元数据)放进方法区,不占堆内存。
  2. 遇到 new 时(实例化):运行时系统查阅方法区的蓝图,在堆(Heap)上精确地切出一块内存,把对象的字段数据放进去,并在对象头(Object Header)里留下一个指针,指回方法区的蓝图。
  3. 遇到 = 时(赋值):把这块堆内存的起始地址(门牌号),放进栈(Stack)上声明好的引用变量里。
using System.Windows.Forms;namespace ClassAnd
{internal class Program{static void Main(string[] args){Form myForm1;//孩子与气球Form myForm2;Form myForm3;Form myForm4; //孩子不牵气球myForm1 = new Form();//孩子与气球myForm2 = new Form();//$1myForm3 = new Form();new Form();//没有孩子牵气球myForm2 = myForm1; //多个孩子可以使用各自的绳子牵着同一个气球 $1myForm1.Text = "Think and ";myForm2.Text = "Live";myForm1.ShowDialog(); // LivemyForm2.ShowDialog(); // Livebool result1 =  myForm1   == myForm2; //在$1中将myForm2中存储的原始内存地址改成myForm1存储的地址。myForm2在$1时创建的内存空间被回收bool result2 =  myForm1   == myForm3;Console.WriteLine(result1); //TrueConsole.WriteLine(result2); //False//Console.WriteLine(myForm4);//CS0165:使用了未赋值的局部变量”myForm4”Console.WriteLine("=======================");(new Form()).Text  = "匿名对象";//没有真正的实例化,不能正确显示(new Form()).ShowDialog();}}
}

类的成员

1. 数据成员(状态/数据)

数据成员用于存储对象或类的状态信息,是类的“静态骨架”。

  • 字段(Fields)
    • 定义:在类内部直接声明的变量,是原始的数据存储单元。
    • 最佳实践:通常声明为 private(私有),用于内部存储,防止外部随意篡改。例如:private string _name;
  • 常量(Constants)
    • 定义:在编译时确定且不可更改的固定值。
    • 特点:属于类的静态特征,所有实例共享。例如:public const string Species = "Homo Sapiens";
  • 属性(Properties)
    • 定义:字段的扩展,提供对数据的受控访问(包含 getset 访问器)。
    • 核心价值:充当“守门人”,可以在赋值或读取时加入验证逻辑(如防止年龄为负数),完美体现了面向对象的封装特性。例如:public int Age { get; set; }
  • 索引器(Indexers)
    • 定义:允许对象像数组一样通过下标(如 [])来访问内部集合数据。
    • 用途:为自定义集合类提供便捷的访问语法。例如:public string this[int index] { get; set; }
2. 函数成员(行为/操作)

函数成员定义了类可以执行的动作、响应机制以及自定义规则。

  • 方法(Methods)
    • 定义:包含具体执行逻辑的代码块,用于定义对象的行为。
    • 特点:可接收参数并返回值,是类对外暴露的核心功能。例如:public void Introduce() { ... }
  • 事件(Events)
    • 定义:基于委托的通知机制,用于在特定条件满足时向外部发送信号。
    • 用途:实现“观察者模式”,解耦对象间的交互(例如按钮点击、状态改变通知)。例如:public event Action OnBirthday;
  • 运算符重载(Operators)
    • 定义:为自定义类型赋予预定义运算符(如 +, -, ==)的新含义。
    • 特点:必须声明为 public static 方法,使自定义对象能像基本数据类型一样参与运算。例如:public static Person operator +(Person p1, Person p2)
3. 生命周期与嵌套成员

这类成员负责管理对象的诞生、消亡以及内部结构的组织。

  • 构造函数(Constructors)
    • 定义:与类同名、无返回类型的特殊方法,在对象被 new 创建时自动调用。
    • 职责:负责初始化对象的初始状态(给字段和属性赋初值)。例如:public Person(string name, int age) { ... }
  • 终结器/析构函数(Finalizers)
    • 定义:以 ~ 开头的方法,在对象即将被垃圾回收器(GC)销毁前由运行时自动调用。
    • 职责:用于清理非托管资源(如文件句柄、数据库连接)。在现代 C# 开发中极少手动编写,通常由 GC 自动管理。例如:~Person() { ... }
  • 嵌套类型(Nested Types)
    • 定义:声明在另一个类内部的类、结构体或枚举。
    • 用途:用于封装仅服务于外部类的辅助逻辑,隐藏内部实现细节,避免污染全局命名空间。例如:public class Address { ... }

[!TIP]

模型类或对象重在属性,如EntityFramework
工具类或对象重在方法,如Math,Console
通知类或对象重在事件,如各种Timer

http://www.zskr.cn/news/1519450.html

相关文章:

  • 【无人机分配】基于纳什均衡和遗传算法进行无人机群目标分配附Matlab代码
  • 2026年AI论文写作工具实测报告:5款神器从文献到降重一站式避坑指南
  • 2026金融行业香港EMBA客观测评与理性选型指南 - 品牌2026推荐
  • N皇后遗传算法实战:Python手写GA核心代码与调参精髓
  • 高层次综合设计乒乓buffer(double-buffer/pingpong-buffer)
  • 少走弯路:盘点2026年王者级的AI论文写作工具
  • 嵌入式开发硬核技能:SPI与Quad Timer寄存器级编程实战解析
  • 别光看理论!拆解MIPS指令字:LW、SW这些信号在CPU单总线里到底怎么‘蹦’出来的?
  • 2026年6月评价高的电加热器实力厂家哪家靠谱,小型导热油加热器/反应釜油加热器/空气电加热器,电加热器企业哪家强 - 品牌推荐师
  • LangChain工程化实践:从提示词到AI原生架构
  • 从IG发送器到CAPL脚本:手把手调试CAN(FD)报文属性(BRS/FDF/BitCount)
  • 值得信赖的高端油烟机生产厂家推荐 - 速递信息
  • 手把手教你玩转CAPL Message:从IG发送器触发到自定义报文解析的完整流程
  • 从SerDes到8B/10B:深入拆解Xilinx 7系列GTX收发器的PMA与PCS子层工作原理
  • Unlock Music终极指南:5分钟掌握加密音乐解密技巧,释放你的音乐自由![特殊字符]
  • R3nzSkin终极实战指南:英雄联盟皮肤修改技术的深度解析与进阶应用
  • 别再只用get_price了!Ptrade实盘交易中获取历史数据的3种替代方案(含完整代码)
  • Cherry Markdown企业级文档自动化解决方案:架构设计与实施指南
  • 2026年6月便携式浊度计知名品牌排行榜:国产替代浪潮下的技术实力与场景适配性深度研判 - 液体流量液位品牌推荐
  • GDB 进程概念详解(上篇)—— 基础原理与单进程调试
  • 微服务文档协作困境:基于Cherry Markdown的企业级知识管理架构实践
  • Cursor Free VIP:破解AI编程助手限制的技术实现与深度应用指南
  • Anthropic 2026 最新 Agent Harness 架构拆解:Managed Agents
  • 从零搭建一个简易网络摄像头:手把手教你用Python+ONVIF+RTSP玩转视频流(附源码)
  • 深入Si24R1芯片:G01-S模块寄存器配置详解与Arduino驱动优化指南
  • 如何彻底掌控AMD处理器性能?开源调试工具SMUDebugTool终极指南
  • 3分钟快速解密音乐文件:Unlock Music浏览器工具终极指南
  • DBeaver驱动包终极解决方案:一键搞定30+数据库连接配置
  • 别再傻傻分不清!用示波器实测SDP/CDP/DCP,手把手教你读懂USB BC1.2握手信号
  • Agent 的骨架:一文讲透 Agent Runtime