CodeGym /课程 /C# SELF /构造函数重载

构造函数重载

C# SELF
第 16 级, 课程 4
可用

1. 入门

假设我们有个Person类:

public class Person
{
    public string Name;
    public int Age;
    
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

你是不是觉得自己快成天才了——可以随便创建带名字和年龄的人。但问题来了:有时候信息不够!比如用户只输入了名字,年龄要晚点才知道。或者你想有时候给个“默认”年龄。你当然可以想点别的办法,但C#有个优雅的解决方案——构造函数重载。

构造函数重载就是一个类可以有多个同名构造函数(和类名一样),但参数列表不同。

这些参数列表有啥区别?可以有这些不同:

  1. 参数数量:比如一个构造函数2个参数,另一个3个。
  2. 参数类型:一个是(string, int),另一个是(string, decimal)。
  3. 参数顺序:(string, int)和(int, string)——这俩签名不一样。

最重要的规则:编译器是靠签名区分构造函数(和任何方法)的。签名包括构造函数(或方法)名和参数列表(数量、类型、顺序)。访问修饰符(public、private)和普通方法的返回类型不算签名一部分。构造函数没有返回类型,名字总和类名一样。

2. 构造函数重载:语法和例子


public class Cat
{
    public string Name;
    public string Color;

    // 无参数构造函数
    public Cat()
    {
        Name = "无名猫";
        Color = "灰色";
    }

    // 一个参数的构造函数
    public Cat(string name)
    {
        Name = name;
        Color = "灰色";
    }

    // 两个参数的构造函数
    public Cat(string name, string color)
    {
        Name = name;
        Color = color;
    }
}

用法:

Cat cat1 = new Cat(); // "无名猫", "灰色"
Cat cat2 = new Cat("穆尔兹克"); // "穆尔兹克", "灰色"
Cat cat3 = new Cat("瑞吉克", "橙色"); // "瑞吉克", "橙色"

创建对象时你传啥参数,C#会根据参数数量和类型自动选对的构造函数。

这真的很方便!用你这个类的人不用填他不知道的参数:只想要只猫——用无参数构造函数,知道名字——用另一个,想指定颜色——用第三个。

3. 构造函数重载怎么选?

C#会在编译时自动根据你传的参数类型和数量选对的构造函数。很难出错——要是搞错了,编译器会直接报错。

我们加个带int参数的构造函数试试:

public Cat(int age)
{
    Name = "无名猫";
    Color = "灰色";
    // 年龄相关的代码
}

现在我们还能按年龄创建“猫咪”:

Cat oldCat = new Cat(5); // 会调用Cat(int age)构造函数
构造函数调用 会调用哪个?
new Cat()
无参数
new Cat("穆尔卡")
一个string参数
new Cat("瑞吉克", "橙色")
两个string参数
new Cat(10)
一个int参数

4. 构造函数内部调用:this关键字

有时候不同构造函数做的事差不多。为了不复制代码,可以“一个构造函数里调用另一个”。这就用this关键字。


public class Cat
{
    public string Name;
    public string Color;

    public Cat() : this("无名猫")
    {
        // 这个构造函数会调用Cat(string name)
    }

    public Cat(string name) : this(name, "灰色")
    {
        // 这个构造函数会调用Cat(string name, string color)
    }

    public Cat(string name, string color)
    {
        Name = name;
        Color = color;
    }
}

结果就是:

  • new Cat()会调用Cat(string name),它又会调用Cat(string name, string color)。
  • 所有“路都通罗马”:所有初始化都集中在一个“主”构造函数里。

这种写法叫constructor chaining(构造函数链式调用)。

5. 生活中的例子

来写个游戏里的英雄类(Hero),有名字和等级!代码如下:

只有一个构造函数:

public class Hero
{
    public string Name;
    public int Level;

    public Hero(string name, int level)
    {
        Name = name;
        Level = level;
    }
}

现在我们让它能多种方式创建!

多个构造函数:

public class Hero
{
    public string Name;
    public int Level;

    // 如果啥都没填,英雄就是“无名”1级
    public Hero() : this("无名", 1)
    {
    }

    // 只知道名字,等级默认1
    public Hero(string name) : this(name, 1)
    {
    }

    // 最全的构造函数
    public Hero(string name, int level)
    {
        Name = name;
        Level = level;
    }
}

现在可以这样创建英雄:

Hero h1 = new Hero();               // "无名", 1
Hero h2 = new Hero("阿图尔");        // "阿图尔", 1
Hero h3 = new Hero("洛拉", 10);     // "洛拉", 10

6. 实现细节:隐藏的坑和注意点

第一:如果你自己写了任何一个构造函数,编译器就不会自动帮你生成“空”构造函数。所以如果你写了带参数的构造函数,但忘了写无参数的,这样写:

Hero h = new Hero(); // 没有无参数构造函数会报错!
会编译报错。

第二:构造函数链里要是调用错了,初始化逻辑就乱了。最好所有实际初始化都放在最全的构造函数里,其他的只用this(...)把数据传过去。

第三:如果参数只差类型(比如Cat(string s)和Cat(object o)),用null做参数时可能会让编译器懵圈,不知道你想调哪个构造函数。

7. 重载和字段初始化

类里经常有些字段必须要赋值。构造函数重载让你方便地做到这一点,但默认值要你自己决定啥合适。

带校验的例子:

public class Book
{
    public string Title;
    public int Year;

    // 默认书名“无标题”,年份2000
    public Book() : this("无标题", 2000)
    {
    }
    
    public Book(string title) : this(title, 2000)
    {
    }

    public Book(string title, int year)
    {
        Title = title;
        Year = year;
    }
}

8. 不同参数组合的重载

有的类构造函数能有几十个!这不一定是好架构(有时候用“配置”方法或builder模式更好),但对用户对象、模型、DTO来说——很常见。

例子:一个“宠物”类,可以全填,也可以只填最重要的。

public class Pet
{
    public string Name;
    public int Age;
    public string Type;
    public bool IsVaccinated;

    // 默认构造函数
    public Pet() : this("NoName", 0, "Cat", false) { }

    // 最少信息
    public Pet(string name, string type) : this(name, 0, type, false) { }

    // 最全的构造函数
    public Pet(string name, int age, string type, bool isVaccinated)
    {
        Name = name;
        Age = age;
        Type = type;
        IsVaccinated = isVaccinated;
    }
}
方法重载和构造函数重载的区别
普通方法 构造函数(包括重载)
随时都能调用 只有创建对象时(new)才会调用
可以返回任意类型的值 永远不返回值(没有类型)
方法名随便起,通常是动词 名字总和类名一样
可以按参数重载 也可以按参数重载
2
任务
C# SELF, 第 16 级, 课程 4
已锁定
创建带有构造函数重载的类
创建带有构造函数重载的类
2
任务
C# SELF, 第 16 级, 课程 4
已锁定
通过 `this` 调用构造函数
通过 `this` 调用构造函数
1
调查/小测验
类和对象的概念第 16 级,课程 4
不可用
类和对象的概念
类和构造函数
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION