this 关键字
本教程共 100 篇 · 第 32 篇 · 更新于 2026-07-31 · 约 11 分钟阅读
32. this 关键字
本节目标:学完你能用
this分清字段和参数,并用它串联构造、传递自身。
this 指的是「当前这个对象自己」。在类的方法里写 this,就相当于指着正在被操作的那个实例说「是我」。它主要干三件事:区分同名、链式构造、传递自身。
用 this 区分字段与参数
最常见的场景:构造函数或方法的参数名,和类的字段名撞了。这时不加 this,编译器分不清谁是谁,默认指向更近的参数。加 this. 明确指向字段,歧义立刻消失。
namespace CSharpDemo;
class Person
{
public string Name;
public Person(string name)
{
this.Name = name; // 左边是字段,右边是参数
}
}
Tip新手建议:命名时给参数加前缀(如
_name)也能避开冲突。但用this.字段是最直白、最不容易看错的写法,团队里也很常见。
如果不写 this 会怎样?看下面的对比,Name = name 把参数赋给了参数自己,字段依然是 null。
namespace CSharpDemo;
class Demo
{
public string Name;
public Demo(string name)
{
Name = name; // 这里没冲突,参数名和字段不同,正常
}
}
当参数也叫 name 却漏了 this,就会出现「赋值无效」的隐蔽 bug,调试半天找不到原因。
this() 链式调用构造函数
上一章讲过,this(...) 让一个构造去调用同类的另一个构造。这里再强调一次它的价值:把多套构造的公共逻辑收敛到一处,避免复制粘贴。
namespace CSharpDemo;
class Student
{
public int Id;
public string Name;
public int Score;
public Student(int id, string name, int score)
{
Id = id;
Name = name;
Score = score;
}
public Student(int id, string name) : this(id, name, 0)
{
}
public Student() : this(0, "未知", 0)
{
}
}
var s = new Student(1, "小华");
Console.WriteLine($"{s.Name} 分数 {s.Score}"); // 小华 分数 0
Note
this(...)必须写在构造的:后面,且它的调用会先于本构造体执行。链式要从「最全的那个」往外派生,别形成环。
把 this 作为参数传递
this 代表当前对象,所以能把「自己」传给别的方法。典型用途是注册回调、把对象交给一个工具方法处理,或实现「把自己加进集合」。
namespace CSharpDemo;
class Logger
{
public static void Print(Person p)
{
Console.WriteLine($"记录:{p.Name}");
}
}
class Person
{
public string Name;
public void Report()
{
Logger.Print(this); // 把当前 Person 交给 Logger
}
}
var p = new Person { Name = "小强" };
p.Report();
这里 Report 里用 this 把自身传进 Logger.Print。读代码时一眼能看出「传的就是我自己」。
this 不能在哪里用
this 只在「实例成员」里有意义。在 static 方法里没有「当前对象」可言,写 this 会直接报错。
namespace CSharpDemo;
class Calc
{
public static int Add(int a, int b) => a + b;
// 静态方法里不能用 this,因为它不属于某个实例
}
Tip记一个口诀:有对象才有
this,static没有对象,所以static里没有this。
this 在底层是什么
从内存视角看,对象的数据存放在托管堆上,this 就是指向「当前这块数据」的引用。每个实例方法其实都隐含地多了一个 this 参数——调用 p.Report() 时,系统把 p 作为 this 传进去。所以方法内部才能知道自己在操作哪个对象。
namespace CSharpDemo;
class Counter
{
public int Value;
public void Add(int n) => Value += n; // 等价于操作 this.Value
}
理解这一点,就能明白为什么 static 方法没有 this:它不属于某个对象,自然没有「当前对象」可传。
this 作返回值:写出链式调用
方法里写 return this;,就能把「自己」交回去,从而连续点出多个调用,这种风格叫流式(fluent)API。
namespace CSharpDemo;
class Builder
{
private List<string> items = [];
public Builder Add(string s)
{
items.Add(s);
return this; // 返回当前实例,继续链式
}
public void Show() => Console.WriteLine(string.Join(",", items));
}
new Builder().Add("笔").Add("本").Add("尺").Show();
Tip返回
this时要确认方法确实在「配置当前对象」,别在会新建对象的方法里误用,否则链式会串错对象。
多层构造的 this 链
this(...) 可以层层往下派生。下面三级构造都最终归到最全的那个,避免重复。
namespace CSharpDemo;
class Order
{
public int Id;
public string Address;
public decimal Price;
public Order(int id, string address, decimal price)
{
Id = id; Address = address; Price = price;
}
public Order(int id, string address) : this(id, address, 9.99m) { }
public Order(int id) : this(id, "未知地址") { }
}
Console.WriteLine(new Order(1).Price); // 9.99
命名约定:避免同名冲突的另一种思路
除了 this.字段,有人喜欢给私有字段加前缀(如 _name)或后缀,让参数直接写 name 也不冲突。两种风格都常见,关键是团队统一。
Note常见误区:在
static方法里写this会立即报错,因为静态成员没有「当前对象」。记住「有对象才有 this」就不会错。
在 lambda 里捕获 this
在实例方法内部的 lambda 表达式中,可以直接使用 this 访问对象成员,因为 lambda「捕获」了当前实例。下面的计数器每秒(示意)回调时仍能改到 total。
namespace CSharpDemo;
class Clock
{
private int total;
public void Start()
{
Action tick = () => { total++; Console.WriteLine(total); };
tick();
tick();
}
}
new Clock().Start(); // 1 然后 2
Notelambda 捕获
this会间接延长对象生命周期,因为委托持有了对实例的引用。短生命周期对象被长生命周期委托捕获,可能导致内存暂不清。
什么时候其实不必写 this
当参数和字段不同名时,写不写 this 结果一样。此时硬加 this. 反而显得啰嗦。约定是:只有「能消除歧义」或「强调这是实例成员」时才写。
namespace CSharpDemo;
class Person
{
public string Name;
public void Set(string value) => Name = value; // 没冲突,可省 this
}
Tip新手另一个误区:在
static方法里写this会立即报错,因为静态成员没有「当前对象」。记住「有对象才有 this」就不会错。
this 在结构里同样成立
this 不只属于类,值类型 struct 的实例方法里也有 this,指向当前那个值。其行为一致:区分字段与参数、传递自身都照常工作。
namespace CSharpDemo;
struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
this.X = x; // 结构里同样用 this 区分
this.Y = y;
}
}
var p = new Point(2, 3);
Console.WriteLine($"({p.X},{p.Y})"); // (2,3)
静态类没有 this
不仅是静态方法,整个静态类都没有实例,自然不存在 this。在静态类里任何地方写 this 都会报错。这与「实例成员才有 this」是同一句话的两面。
Note一句话记牢:只要写
this,就一定处在「某个具体对象」的上下文里;static无论方法还是类,都脱离具体对象,所以都没有this。
一个易错点:this 不能进静态初始化
静态字段的初始化器里不能用 this,因为静态字段属于类、早于任何对象存在,此时「当前实例」根本还没出生。
namespace CSharpDemo;
class Demo
{
// private static int x = this.Y; // 错误:静态上下文无 this
public int Y;
}
Note这条规则和「静态方法不能有 this」是同一根源:凡是
static的领域,都不存在具体对象,自然没有this可用。
this 为什么这样设计
this 不是凭空多出来的。C# 的实例方法在底层都隐含携带一个「当前对象」引用——调用 p.Report() 时,运行时把 p 一并传进去,方法体内才认得 this 是谁。把这件事显式暴露成 this 关键字,好处是:方法内部既能访问自己的字段,又能在「字段和参数同名」时精准指定目标。换句话说,this 是「实例方法天然拥有当前对象」这一事实的语法出口。
Note正因为
this代表「当前对象」,它不能被赋值为别的实例(写this = other;非法),也不能当ref/out参数传出去——它扮演的是只读的「我是谁」。
this 与下划线前缀:两种风格怎么选
区分「字段 vs 参数」,业界有两类常见写法:
- 用
this.字段:直观,谁都能一眼看出指向实例成员; - 给私有字段加
_前缀(如private string _name;),参数直接写name,天然不冲突。
两种都对,关键在团队统一。本书示例偏向 this.字段,因为零基础读者最不容易看错。C# 12 还引入了主构造器(primary constructor),参数直接成为字段,连 this 都不用写:
namespace CSharpDemo;
class Person(string name) // name 已是字段,无需 this 区分
{
public void Show() => Console.WriteLine(name);
}
Tip用主构造器时,参数名就是字段名,根本不会出现同名冲突,也就不需要
this来救场。这是现代 C# 推荐的写法。
常见误区与最佳实践
- 只在必要处写
this:参数与字段不同名时,加this.纯属噪音;有歧义或想强调「这是实例成员」才写。 static里绝不用this:静态方法/静态类没有「当前对象」,写this立即报错。return this要谨慎:它适合「配置当前对象」的流式 API,别在会新建对象的方法里误用,否则链式会串错对象。- 别在 property 的
get里用this做重活:读取属性本应轻快,若this触发大量计算,调用方会误以为很便宜。
小结
this 指「当前实例」,底层是指向对象数据的引用,实例方法(包括 struct 的实例方法)都隐含带着它。写 this.字段 能在参数同名时精准命中字段;this(...) 把多个构造函数串起来去重;把 this 当参数能方便地把自身交给别的方法;return this 还能写出链式调用;lambda 也会捕获 this 来访问实例成员。而在 static 上下文里(无论静态方法还是静态类,包括静态字段初始化器),因为它不挂靠任何对象,不能使用 this。当参数与字段不同名时,写 this 并非必须。