链式重载构造函数?

时间:2009-10-05 13:15:33

标签: c# constructor

我正在尝试构建一个类,它将通过传入对数据库中的记录的引用来启动它自己(意图是对数据库运行查询并且对象属性的返回值将会在其中设置),或通过“手动”指定值 - 这不需要数据库调用。

我看了几本教科书,发现了这项功能的“最佳实践”,遗憾的是我已经做错了。

我写了几个示例控制台应用程序,反映了我认为最可能的两个解决方案,但我不知道哪个是最好的正确实现?

示例应用程序#1使用了大多数书籍告诉我的“首选”方式,但大多数示例与这些声明并不符合我的情况。我在这里担心流程不如App#2那么可读。

using System;

namespace TestApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var one = new OverloadedClassTester();
            var two = new OverloadedClassTester(42);
            var three = new OverloadedClassTester(69, "Mike", 24);

            Console.WriteLine("{0}{1}{2}", one, two, three);

            Console.ReadKey();
        }        
    }

    public class OverloadedClassTester
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int age { get; set; }

        public OverloadedClassTester() : this(0) { }

        public OverloadedClassTester (int _ID) : this (_ID, "", 0)
        {
            this.age = 14;  // Pretend that this was sourced from a database
            this.Name = "Steve"; // Pretend that this was sourced from a database
        }

        public OverloadedClassTester(int _ID, string _Name, int _age)
        {
            this.ID = _ID;
            this.Name = _Name;
            this.age = _age;
        }

        public override string ToString()
        {
            return String.Format("ID: {0}\nName: {1}\nAge: {2}\n\n", this.ID, this.Name, this.age);
        }
    }
}

此示例(App#2)“看起来”更具可读性 - 因为我认为更容易看到操作流程。然而,就保存的字符而言,它看起来确实有效:p。此外,它在完全初始化之前调用对象的方法是不是很危险,或者这不是一个问题?

using System;

namespace TestApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var one = new OverloadedClassTester();
            var two = new OverloadedClassTester(42);
            var three = new OverloadedClassTester(69, "Mike", 24);

            Console.WriteLine("{0}{1}{2}", one, two, three);

            Console.ReadKey();
        }        
    }

    public class OverloadedClassTester
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int age { get; set; }

        public OverloadedClassTester()
        {
            initialise(0, "", 21); // use defaults.
        }

        public OverloadedClassTester (int _ID)
        {
            var age = 14;  // Pretend that this was sourced from a database (from _ID)
            var Name = "Steve"; // Pretend that this was sourced from a database (from _ID)

            initialise(_ID, Name, age);
        }

        public OverloadedClassTester(int _ID, string _Name, int _age)
        {
            initialise(_ID, _Name, _age);
        }

        public void initialise(int _ID, string _Name, int _age)
        {
            this.ID = _ID;
            this.Name = _Name;
            this.age = _age;
        }

        public override string ToString()
        {
            return String.Format("ID: {0}\nName: {1}\nAge: {2}\n\n", this.ID, this.Name, this.age);
        }
    }
}

解决这个问题的“正确”方法是什么?为什么?

谢谢,

5 个答案:

答案 0 :(得分:12)

我肯定会链接构造函数,因此只有一个才能完成“实际工作”。这意味着你只需要在一个地方真正的工作,所以如果这项工作发生了变化(例如你需要在构造函数的末尾调用一些验证方法),你只需要一个你需要的地方改变代码。

使用更多参数进行“简单”重载调用重载是一种非常常见的模式IME。我发现它比第二个版本的更多可读,因为您可以轻松地告诉调用一个重载与使用默认值调用“更大”的重载相同。对于第二个版本,您必须比较构造函数的主体。

我尽量不要有多个构造函数尽可能直接链接到基类 - 除非它链接到不同的基类构造函数,当然(通常情况下除外)。

答案 1 :(得分:2)

不要在构造函数中使用数据库调用。这意味着你的构造函数正在做很多工作。请参阅http://misko.hevery.com/code-reviewers-guide/(编写可测试代码的Google指南)。

除此之外,链接构造函数(选项2)看起来很好。主要是因为你说它是可读的。但是为什么要在构造函数中分配this.Name等并在初始化中再次执行它。您可以在初始化中分配所有值。

答案 2 :(得分:1)

也许是这样的?

public class OverloadedClassTester
{
    public int Id { get; private set; }
    public string Name { get; private set; }
    public int Age { get; private set; }


    public OverloadedClassTester (Person person)
      : this (person.Id, person.Name, person.Age) { }

    public OverloadedClassTester(int id, string name, int age)
    {
        Id = id;
        Name = name;
        Age = age;
    }

    public override string ToString()
    {
        return String.Format("Id: {0}\nName: {1}\nAge: {2}\n\n", 
            Id, Name, Age);
    }
}

答案 3 :(得分:0)

也许最好使用可选参数?在这种情况下,您将创建一个构造函数并将值初始化为您要设置的参数。

更多信息:link text

答案 4 :(得分:0)

从维护的角度来看,我更喜欢链接构造函数#1。当有人回来编辑代码时,您不希望他们编辑initialise()方法,也不会意识到它是从构造函数中调用的。我认为在某种构造函数中包含所有功能部件更为直观。

就个人而言,我一直使用构造函数链接。