C# 方法详解:语法结构、访问修饰符与分类实战
C#作为完全面向对象的编程语言,其核心功能单元被称为“方法”。本文详细解析方法的基本声明格式、访问修饰符的有效组合,并重点对比静态与实例方法、虚与非虚方法、外部及分部方法的使用场景与差异。
一、方法基础与声明规范
在C#中,类中自定义的函数被称为方法。方法是已命名的语句集合,用于实现对象或类可执行的操作。每个方法包含名称和主体(方法体),通常提供输入数据并返回处理结果。
第1步:掌握方法的标准声明格式
方法声明的基本语法如下:
修饰符 返回值类型 方法名称(参数列表) { 方法体 }
- 修饰符:决定方法的访问级别和行为特征。常用的修饰符包括
public、private、static、virtual、sealed、override、abstract、extern、partial等。 - 返回值类型指定返回数据的类型;若不返回值,需使用关键字
void。若使用了partial修饰符,返回值必须为void。 - 参数列表中的形参名不能重复,且方法名不得与类中其他成员重名。
第2步:理解修饰符的有效性组合
C#对修饰符的组合有严格限制,有效的修饰符组合需满足以下条件:
- 访问修饰符组合有效(如
public不与private同时出现)。 - 修饰符无重复项。
- 最多包含一个:
static、virtual或override。 - 最多包含一个:
new或override。 - 若含
abstract,则不可包含static、virtual、sealed或extern。 - 若含
private,则不可包含virtual、override或abstract。 - 若含
sealed,必须包含override。 - 若含
partial,不能包含任何访问修饰符及其他行为修饰符。
第3步:编写一个简单的加法方法
以下是返回两个整型和值的典型实例方法:
public int add(int a, int b)
{
return a + b;
}
二、静态方法与实例方法
根据所属对象的不同,方法主要分为静态方法和实例方法。理解二者区别是避免编译错误的关键。
第4步:区分静态与实例方法的访问范围
- 静态方法(
static)属于类本身,不属于特定实例。只能访问类的静态成员,不能使用this关键字。调用时必须通过类名进行。 - 实例方法属于类的具体对象。可以访问静态成员和实例成员,可以使用
this引用当前对象。调用时必须先创建对象实例。
之所以禁止静态方法访问实例成员,是因为静态方法在执行时可能并不存在具体的对象,而实例成员必须依附于对象存在。
第5步:通过示例验证访问规则
以下代码展示了在类中定义实例变量、静态变量及其对应方法的调用逻辑:
using System;
namespace Text
{
class A
{
int exaVar; // 实例成员变量
static int stVar; // 静态成员变量
void tM() // 实例方法
{
exaVar = 1; // 等价于 this.exaVar = 1
stVar = 1; // 等价于 A.stVar = 1
}
static void sM() // 静态方法
{
// exaVar = 1; // 错误!静态方法无法直接访问实例成员
stVar = 1; // 正确,访问静态成员
}
static void Main(string[] args)
{
A text = new A();
text.exaVar = 1; // 正确:通过对象访问实例成员
A.stVar = 1; // 正确:通过类访问静态成员
text.tM(); // 正确:调用实例方法
A.sM(); // 正确:调用静态方法
Console.WriteLine(text.exaVar + A.stVar);
Console.ReadLine();
}
}
}
上述程序输出结果为 2。注意:尝试通过对象调用静态方法(如 text.sM())或在静态方法中引用实例变量均会导致编译错误。
三、虚方法与非虚方法
在多态性实现中,虚方法允许派生类重写基类行为,而非虚方法的实现则是固定的。
第6步:实现非虚方法的隐藏(New)
若派生类定义了与基类同名的方法但未使用 override,而是使用 new 修饰符,则称为“隐藏”了基类方法。此时,调用哪个版本取决于变量的声明类型(编译时类型)。
第7步:利用虚方法(Virtual)实现多态
当基类方法声明为 virtual 时,派生类可用 override 替换其实现。此时,调用哪个版本取决于变量的运行时类型(实际指向的对象)。这体现了面向对象的多态特性。
第8步:观察输出结果差异
以下代码演示了 B 继承 A 的情况:
using System;
namespace Text {
public class A {
public virtual void ab() { Console.WriteLine("这是虚方法"); }
public void ac() { Console.WriteLine("这是非虚方法"); }
}
public class B : A {
public override void ab() { Console.WriteLine("这是新的方法"); }
public new void ac() { Console.WriteLine("这是另一个新的方法"); }
}
class Program {
static void Main() {
B b = new B();
A a = b;
a.ab(); // 输出:这是新的方法 (基于运行时类型 B)
b.ab(); // 输出:这是新的方法
a.ac(); // 输出:这是非虚方法 (基于编译时类型 A)
b.ac(); // 输出:这是另一个新的方法
}
}
}
程序的输出结果如下所示:
四、虚方法与重写方法细节
使用 override 重写基类方法需遵循严格的契约规则,以确保兼容性。
第9步:重写时的注意事项
- 签名匹配:重写方法必须与被覆盖的方法具有完全相同的标志(名称和参数列表)。
- 返回值一致:返回类型必须相同。
- 异常兼容:抛出的异常应相同或是原异常的子类。
- 可访问性不降级:重写方法的访问权限不能低于基类方法。若基类方法为
protected且跨程序集,重写方法必须声明为protected。 - 基类不能为 private:若基类方法为
private,则在子类中定义的只是新方法来,并未发生真正的重写。
第10步:验证重写效果
以下代码展示了通过不同对象调用同一个被重写的虚方法:
using System;
namespace Text {
class A {
public virtual void a() { Console.WriteLine("这是虚方法"); }
}
class B : A {
public override void a() { Console.WriteLine("这是重写后的方法"); }
}
class Program {
static void Main() {
B b1 = new B();
b1.a(); // 输出:这是重写后的方法
A a1 = new A();
a1.a(); // 输出:这是虚方法
A a2 = b1; // 向上转型,但运行时仍为B类型
a2.a(); // 输出:这是重写后的方法
}
}
}
输出证实:只要引用的对象本质是派生类,即使以基类类型变量接收,调用的依然是派生类的重写实现。
五、外部方法与分部方法
第11步:调用底层 DLL(外部方法)
外部方法由 extern 修饰,通常在C#之外的语言(如C/C++)中实现。常配合 DllImport 属性使用以调用Windows系统DLL(如 User32.dll)。
要点:
- 引入命名空间:
System.Runtime.InteropServices。 - 必须标记为
static。 - 常用于平台调用服务(P/Invoke)。
调用用户提示框示例:
using System;
using System.Runtime.InteropServices;
namespace Text {
class Program {
[DllImport("User32.dll")]
public static extern int MessageBox(int H, string m, string c, int type);
static int Main(string[] args) {
Console.Write("请输入信息:");
string str = Console.ReadLine();
return MessageBox(0, str, "我的信息提示框", 0);
}
}
}
运行程序后,将弹出一个自定义标题的系统消息框:
第12步:使用分部方法(Partial Methods)
分部方法主要用于代码生成器生成的文件中。它的核心价值在于:**如果未实现该方法的主体,编译器会将其所有调用和声明从最终代码中剔除**,不会引起额外的性能损耗或代码膨胀。
约束条件:
- 必须在分部类或分部结构内声明。
- 隐式私有(不能添加访问修饰符)。
- 不能有返回值(必须是
void)。 - 不能有输出参数(
out)。
第13步:验证分部方法的生效与消失
在以下示例中,我们定义了 text 分部方法。由于我们在同一项目的另一部分实现了它,调用将被执行:
using System;
namespace Text {
public partial class Program {
private int _setup;
public int setup {
set { _setup = value; }
get { return _setup; }
}
partial void text(int t); // 声明
}
partial class Program {
partial void text(int t) { // 实现
t += _setup;
Console.Write(t);
}
}
class Entry {
static void Main() {
Program pg = new Program();
pg.setup = 100;
pg.text(50); // 此处调用会触发上面的实现,输出 150
}
}
}
输出结果为 150。若删除了分部方法的实现部分,编译器会自动移除 pg.text(50) 这行代码,使其变成空操作。
总结
掌握C#方法的各种形态与规则,能够显著提升代码的模块化程度。通过合理选择静态/实例、虚/非虚以及分部方法,你可以更灵活地组织类库结构并减少冗余代码。以上就是C# 方法的详细内容,更多关于C#编程入门的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













