构造函数初始化优化?

3

注意:我这里使用的是.NET 3.5。

假设我有以下构造函数的样本基类/子类:

public Person(string name, int age, string job, bool isMale)
{  
    Name = name;
    Age = age;
    Job = job;
    IsMale = isMale;
}  

public CollegeStudent(string name) : this(name, 18) {}

public CollegeStudent(string name, int age) : this(name, age, "Student") {}

public CollegeStudent(string name, int age, string job) : this(name, age, job, true) {}

public CollegeStudent(string name, int age, string job, bool isMale) : base(name, age, job, isMale) {}

编译器是否足够聪明,能够看到子构造函数所做的唯一事情就是彼此链接并最终调用基础构造函数?因此,它可以在编译时直接将"this"构造函数初始化程序更改为直接调用基础构造函数?

因此,在底层,所有内容都将被更改为以下内容:

public CollegeStudent(string name) : base(name, 18, "Student", true) {}

public CollegeStudent(string name, int age) : base(name, age, "Student", true) {}

public CollegeStudent(string name, int age, string job) : base(name, age, job, true) {}

public CollegeStudent(string name, int age, string job, bool isMale) : base(name, age, job, isMale) {}

我希望我的构造函数能够像第一部分那样方便地编写,但是如果我只是要产生无用的开销,我可能会直接为每个构造函数调用基础构造函数。


2
当科学家创建新的性别时,您将遇到问题,应该使用枚举。 - user216441
1
是的,如果这只是一个小例子的话,我会使用枚举。我并不认为这与我的问题相关... - Tedderz
2
只需清晰准确地编写即可,这里没有什么需要优化的。 - H H
5个回答

6

C#编译器会沿着链式构造函数向后遍历,直到到达Object构造函数。当使用链式构造函数时,我认为没有太多需要优化的地方。你可以尝试编译该代码,然后使用Reflector查看优化后的代码。

在此之前,我等待Jon Skeet的回答。

编辑

我刚刚将这个简单的代码编译成了一个类(.Net 3.5):

namespace Person {
    public class Person {
        private String Name;
        private int Age;
        private String Job;
        private Boolean IsMale;

        public Person(string name, int age, string job, bool isMale) {
            Name = name;
            Age = age;
            Job = job;
            IsMale = isMale;
        }
    }

    public class CollegeStudent : Person {
        public CollegeStudent(string name) : this(name, 18) { }
        public CollegeStudent(string name, int age) : this(name, age, "Student") { }
        public CollegeStudent(string name, int age, string job) : this(name, age, job, true) { }
        public CollegeStudent(string name, int age, string job, bool isMale) : base(name, age, job, isMale) { }
    }
}

使用反编译工具Reflector,我发现C#编译器并没有按照你所建议的方式来优化任何构造函数。


最后一个构造函数?如果有这样的优化,不是前三个构造函数会被优化为直接调用base()吗?我认为我不应该期望最后一个构造函数会改变。 - Tedderz
感谢您抽出时间来完成这件事;答案已被接受。 - Tedderz

6
如果要优化这个问题,应该由JIT编译器而不是C#编译器来处理。特别是,如果此代码从不同的程序集调用,则C#编译器不能假定在执行时CollegeStudent中的代码与编译时相同。
像SimpleCoder和Jim所说的那样,你不必太担心这个问题。它成为重大性能问题的可能性微乎其微。
正如Mahesh所说,对于C# 4,您可以使用带有可选参数的单个构造函数,但是您应该知道,即使您针对.NET 2.0或.NET 3.5,任何使用C# 2或C# 3编译器编译针对您代码的人将无法使用某些参数是可选的事实,并且将被强制指定所有参数。

3
如果您使用的是C# 4.0版本,建议使用可选参数,它们更加方便且简洁。
public Person(string name, int age = 18, string job = "Student", bool isMale = true)
{  
    Name = name;
    Age = age;
    Job = job;
    IsMale = isMale;
}

现在您可以使用以下内容:

public CollegeStudent(string name) : base(name) {}

public CollegeStudent(string name, int age) : base(name, age) {}

public CollegeStudent(string name, int age, string job) : base(name, age, job) {}

public CollegeStudent(string name, int age, string job, bool isMale) 
                      : base(name, age, job, isMale) {}

对不起,我应该表达得更清楚;实际上我在使用3.5版本。我会在原帖中添加一条注释。虽然我完全同意在4.0中使用那种语法。 - Tedderz

2

我不知道编译器是否足够聪明,能够消除构造函数相互链接的“无用开销”。但这真的重要吗?你需要问自己的问题是:写第二个版本可能节省的几微秒是否真的值得在可维护性方面付出代价。你真的会调用那么多构造函数吗,每个调用都只能节省几微秒。根本没有关系吧。


那是一个很好的观点。实际上,我正在编写一些数据加载器,用于从各种格式中读取条目并将它们加载到ADAM分区中。因此,我最终会为每个条目实例化一个对象,这就是为什么构造函数链接会让我感到担忧的原因,因为数据集非常大。但在大多数情况下,我同意这不是我应该纠结的事情。 - Tedderz

1

你知道新的语法吗:

CollegeStudent student = new CollegeStudent
{
  Name = "Bob",
  Age = 21,
  Job = "Spaceman",
  IsMale = true,
};

现在这样的构造函数应该是不必要的,除非你不得不在较旧版本的Visual Studio中编译。


2
相反,这是依赖于类型可变的情况,而 OP 的代码可能是针对不可变类型的。 - Jon Skeet
2
你的客户如何知道哪些参数是可选的,哪些是必需的? - Sergey Mirvoda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接