C# 方法详解:语法结构、访问修饰符与分类实战

小林子
小林子
发布时间:2026-10-13 | 1人浏览过
原创

C#作为完全面向对象的编程语言,其核心功能单元被称为“方法”。本文详细解析方法的基本声明格式、访问修饰符的有效组合,并重点对比静态与实例方法、虚与非虚方法、外部及分部方法的使用场景与差异。

一、方法基础与声明规范

在C#中,类中自定义的函数被称为方法。方法是已命名的语句集合,用于实现对象或类可执行的操作。每个方法包含名称和主体(方法体),通常提供输入数据并返回处理结果。

第1步:掌握方法的标准声明格式

方法声明的基本语法如下:

修饰符 返回值类型 方法名称(参数列表) { 方法体 }
  • 修饰符:决定方法的访问级别和行为特征。常用的修饰符包括 public、private、static、virtual、sealed、override、abstract、extern、partial 等。
  • 返回值类型指定返回数据的类型;若不返回值,需使用关键字 void。若使用了 partial 修饰符,返回值必须为 void。
  • 参数列表中的形参名不能重复,且方法名不得与类中其他成员重名。

第2步:理解修饰符的有效性组合

C#对修饰符的组合有严格限制,有效的修饰符组合需满足以下条件:

  1. 访问修饰符组合有效(如 public 不与 private 同时出现)。
  2. 修饰符无重复项。
  3. 最多包含一个:static、virtual 或 override。
  4. 最多包含一个:new 或 override。
  5. 若含 abstract,则不可包含 static、virtual、sealed 或 extern。
  6. 若含 private,则不可包含 virtual、override 或 abstract。
  7. 若含 sealed,必须包含 override。
  8. 若含 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步:重写时的注意事项

  1. 签名匹配:重写方法必须与被覆盖的方法具有完全相同的标志(名称和参数列表)。
  2. 返回值一致:返回类型必须相同。
  3. 异常兼容:抛出的异常应相同或是原异常的子类。
  4. 可访问性不降级:重写方法的访问权限不能低于基类方法。若基类方法为 protected 且跨程序集,重写方法必须声明为 protected。
  5. 基类不能为 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#编程入门的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表