C# base和this

本文介绍了C#中base和this关键字的使用方法及其在继承和多态中的作用。通过示例代码展示了如何使用base访问基类成员及this引用当前实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C# basethis

 ——摘自Rocky Ren

  2. 基本概念

  basethisC#中被归于访问关键字,顾名思义,就是用于实现继承机制的访问操作,来满足对对象成员的访问,从而为多态机制提供更加灵活的处理方式。 

  2.1 base关键字

  其用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数、实例方法和实例属性访问器中,MSDN中小结的具体功能包括:

  • 调用基类上已被其他方法重写的方法。

  • 指定创建派生类实例时应调用的基类构造函数。

  2.2 this关键字

  其用于引用类的当前实例,也包括继承而来的方法,通常可以隐藏thisMSDN中的小结功能主要包括:

  • 限定被相似的名称隐藏的成员

  • 将对象作为参数传递到其他方法

  • 声明索引器  

  3. 深入浅出

  3.1 示例为上

  下面以一个小示例来综合的说明,basethis在访问操作中的应用,从而对其有个概要了解,更详细的规则和深入我们接着阐述。本示例没有完全的设计概念,主要用来阐述basethis关键字的使用要点和难点阐述,具体的如下:

 

using System;

namespace Anytao.net.My_Must_net

{

public class Action

{

public static void ToRun(Vehicle vehicle)

{

Console.WriteLine("{0} is running.", vehicle.ToString());

}

}

public class Vehicle

{

private string name;

private int speed;

private string[] array = new string[10];

 

public Vehicle()

{

}

//限定被相似的名称隐藏的成员

        public Vehicle(string name, int speed)

{

this.name = name;

this.speed = speed;

}

public virtual  void ShowResult()

{

Console.WriteLine("The top speed of {0} is {1}.", name, speed);

}

public void Run()

{

//传递当前实例参数

            Action.ToRun(this);

}

//声明索引器,必须为this,这样就可以像数组一样来索引对象

        public string  this[int param]

{

get{return array[param];}

set{array[param] = value;}

}

}

public class Car: Vehicle

{

//派生类和基类通信,以base实现,基类首先被调用

//指定创建派生类实例时应调用的基类构造函数

        public Car()

: base("Car", 200)

{ }

 

public Car(string name, int speed)

: this()

{ }

 

public override void ShowResult()

{

//调用基类上已被其他方法重写的方法

            base.ShowResult();

Console.WriteLine("It's a car's result.");

}

}

public class Audi : Car

{

public Audi()

: base("Audi", 300)

{ }

 

public Audi(string name, int speed)

: this()

}

public override void ShowResult()

{

//由三层继承可以看出,base只能继承其直接基类成员

            base.ShowResult();

base.Run();

Console.WriteLine("It's audi's result.");

}

}

public class BaseThisTester

{

public static void Main(string[] args)

{

Audi audi = new Audi();

audi[1] = "A6";

audi[2] = "A8";

Console.WriteLine(audi[1]);

audi.Run();

audi.ShowResult();

}

}

}

 

  3.2 示例说明

  上面的示例基本包括了basethis使用的所有基本功能演示,具体的说明可以从注释中得到解释,下面的说明是对注释的进一步阐述和补充,来说明在应用方面的几个要点:

  • base常用于,在派生类对象初始化时和基类进行通信。

  • base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。

  • this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成员,而且不管访问元素是任何访问级别。因为,this仅仅局限于对象内部,对象外部是无法看到的,这就是this的基本思想。另外,静态成员不是对象的一部分,因此不能在静态方法中引用this

  • 在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存在的情况下,base将指向直接继承的父类成员的方法,例如Audi类中的ShowResult方法中,使用base访问的将是Car.ShowResult()方法,而不能访问Vehicle.ShowResult()方法;而是没有重载存在的情况下,base可以指向任何上级父类的公有或者受保护方法,例如Audi类中,可以使用base访问基类Vehicle.Run()方法。这些我们可以使用ILDasm.exe,从IL代码中得到答案。

 

.method public hidebysig virtual instance void 

ShowResult() cil managed

{

// 代码大小       27 (0x1b)

  .maxstack  8

IL_0000:  nop

IL_0001:  ldarg.0

//base调用父类成员

  IL_0002:  call       instance void Anytao.net.My_Must_net.Car::ShowResult()

IL_0007:  nop

IL_0008:  ldarg.0

//base调用父类成员,因为没有实现Car.Run(),所以指向更高级父类

  IL_0009:  call       instance void Anytao.net.My_Must_net.Vehicle::Run()

IL_000e:  nop

IL_000f:  ldstr      "It's audi's result."

IL_0014:  call       void [mscorlib]System.Console::WriteLine(string)

IL_0019:  nop

IL_001a:  ret

} // end of method Audi::ShowResult

 

  3.3 深入剖析 

  如果有三次或者更多继承,那么最下级派生类的base指向那一层呢?例如.NET体系中,如果以base访问,则应该是直接父类实例呢,还是最高层类实例呢?

  首先我们有必要了解类创建过程中的实例化顺序,才能进一步了解base机制的详细执行过程。一般来说,实例化过程首先要先实例化其基类,并且依此类推,一直到实例化System.Object为止。因此,类实例化,总是从调用System.Object.Object()开始。因此示例中的类Audi的实例化过程大概可以小结为以下顺序执行,详细可以参考示例代码分析。

  • 执行System.Object.Object();

  • 执行Vehicle.Vehicle(string name, int speed);

  • 执行Car.Car();

  • 执行Car.Car(string name, int speed);

  • 执行Audi.Audi();

  • 执行Audi.Audi(string name, int speed)

  我们在充分了解其实例化顺序的基础上就可以顺利的把握basethis在作用于构造函数时的执行情况,并进一步了解其基本功能细节。

  下面更重要的分析则是,以ILDASM.exe工具为基础来分析IL反编译代码,以便更深层次的了解执行在basethis背后的应用实质,只有这样我们才能说对技术有了基本的剖析。

Main方法的执行情况为:

 

.method public hidebysig static void  Main(string[] args) cil managed

{

.entrypoint

// 代码大小       61 (0x3d)

  .maxstack  3

.locals init (class Anytao.net.My_Must_net.Audi V_0)

IL_0000:  nop

//使用newobj指令创建新的对象,并调用构造函数初始化

  IL_0001:  newobj     instance void Anytao.net.My_Must_net.Audi::.ctor()

IL_0006:  stloc.0

IL_0007:  ldloc.0

IL_0008:  ldc.i4.1

IL_0009:  ldstr      "A6"

IL_000e:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::set_Item(int32,

string)

IL_0013:  nop

IL_0014:  ldloc.0

IL_0015:  ldc.i4.2

IL_0016:  ldstr      "A8"

IL_001b:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::set_Item(int32,

string)

IL_0020:  nop

IL_0021:  ldloc.0

IL_0022:  ldc.i4.1

IL_0023:  callvirt   instance string Anytao.net.My_Must_net.Vehicle::get_Item(int32)

IL_0028:  call       void [mscorlib]System.Console::WriteLine(string)

IL_002d:  nop

IL_002e:  ldloc.0

IL_002f:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::Run()

IL_0034:  nop

IL_0035:  ldloc.0

//base.ShowResult最终调用的是最高级父类Vehicle的方法,

//而不是直接父类Car.ShowResult()方法,这是应该关注的

  IL_0036:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::ShowResult()

IL_003b:  nop

IL_003c:  ret

} // end of method BaseThisTester::Main

因此,对重写父类方法,最终指向了最高级父类的方法成员。

 

  4. 通用规则

  • 尽量少用或者不用basethis。除了决议子类的名称冲突和在一个构造函数中调用其他的构造函数之外,basethis的使用容易引起不必要的结果。

  • 在静态成员中使用basethis都是不允许的。原因是,basethis访问的都是类的实例,也就是对象,而静态成员只能由类来访问,不能由对象来访问。

  • base是为了实现多态而设计的。

  • 使用thisbase关键字只能指定一个构造函数,也就是说不可同时将thisbase作用在一个构造函数上。

  • 简单的来说,base用于在派生类中访问重写的基类成员;而this用于访问本类的成员,当然也包括继承而来公有和保护成员。

  • 除了base,访问基类成员的另外一种方式是:显示的类型转换来实现。只是该方法不能为静态方法。 

 

转载于:https://www.cnblogs.com/zhuyuan28/p/3913350.html

### 关于 `this` `base` 的用法 #### 使用 `this` 关键字 在 C# 中,`this` 是一个关键字,用于引用当前实例或隐藏字段的参数。它通常有以下几个用途: 1. **作为方法参数传递当前对象** 当需要将当前类的对象作为一个整体传递给其他方法时,可以使用 `this` 来表示当前对象[^4]。 ```csharp public class Person { public string Name { get; set; } public void Introduce() { Console.WriteLine($"Hi, my name is {Name}"); } public void Greet(Person other) { Console.WriteLine($"{this.Name} says hello to {other.Name}"); } } var personA = new Person { Name = "Alice" }; var personB = new Person { Name = "Bob" }; personA.Greet(personB); // Alice says hello to Bob ``` 2. **解决命名冲突 (Field Hiding)** 如果局部变量或参数名称与成员变量相同,则可以通过 `this` 明确指定成员变量[^5]。 ```csharp public class Rectangle { private int width; private int height; public Rectangle(int width, int height) { this.width = width; // 解决宽度属性的命名冲突 this.height = height; // 解决高度属性的命名冲突 } public int GetArea() => this.width * this.height; } ``` 3. **返回当前实例** 可以通过 `this` 返回当前实例本身,这常见于链式调用的设计模式中[^6]。 ```csharp public class StringBuilderExample { private string content = ""; public StringBuilderExample Append(string text) { this.content += text; return this; // 支持链式调用 } public override string ToString() => this.content; } var builder = new StringBuilderExample(); Console.WriteLine(builder.Append("Hello").Append(", ").Append("World!")); // Hello, World! ``` --- #### 使用 `base` 关键字 `base` 主要用于访问基类中的成员,在继承关系下非常有用。以下是其主要功能: 1. **显式调用基类构造函数** 子类可以在自己的构造函数中使用 `base` 调用父类的构造函数来初始化共享状态[^7]。 ```csharp public class Animal { protected string sound; public Animal(string s) { this.sound = s; } public virtual void MakeSound() { Console.WriteLine(sound); } } public class Dog : Animal { public Dog() : base("Woof") {} // 基类构造器被调用 } var dog = new Dog(); dog.MakeSound(); // 输出 Woof ``` 2. **覆盖并调用基类的方法实现** 在重写虚方法时,有时可能希望保留部分原有逻辑并通过 `base` 实现这一点[^8]。 ```csharp public class Vehicle { public virtual void StartEngine() { Console.WriteLine("Starting engine..."); } } public class Car : Vehicle { public override void StartEngine() { base.StartEngine(); // 执行基类行为 Console.WriteLine("Car-specific startup logic"); } } var car = new Car(); car.StartEngine(); /* Output: Starting engine... Car-specific startup logic */ ``` 3. **访问受保护的基类成员** 即使子类无法直接看到某些私有的基类成员,也可以借助 `base` 访问它们(前提是这些成员声明为 `protected` 或更高可见性级别)[^9]。 ```csharp public class ParentClass { protected int value; public ParentClass(int v) { this.value = v; } public virtual void ShowValue() { Console.WriteLine(value); } } public class ChildClass : ParentClass { public ChildClass(int v) : base(v) {} public override void ShowValue() { Console.WriteLine(base.value + " from child"); // 使用 base 访问基类成员 } } var child = new ChildClass(42); child.ShowValue(); // 输出 42 from child ``` --- ### 总结 - `this` 用于操作当前实例及其成员。 - `base` 则专注于处理继承层次结构下的基类交互。 两者都提供了强大的工具集,帮助开发者更灵活地控制程序的行为数据流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值