构造函数中的方法,不好?

时间:2011-01-05 14:12:25

标签: c# structure coding-style

我有一个Windows窗体,我有一个类来检查文本文件以确保它具有某些方面。现在我在构造函数中有方法,它看起来有点奇怪。我应该将构造函数留空,并实现一个start()类型方法并调用它?到目前为止,我的代码看起来像这样

public class Seating
{
    private int segments = 0;
    public Seating()
    {
        checkInvoice();
        getSegmentCount();          
    }
}

7 个答案:

答案 0 :(得分:26)

  

我在构造函数中有方法,看起来有点奇怪

那么,为什么还有构造函数存在?在构造函数中使用方法是完全合法的,甚至是可能失败的方法(从而中断对象创建)。很难说这是否适合您的具体情况。

一般情况下它很好。

答案 1 :(得分:8)

在构造函数中调用非虚方法没有错。在构造函数触发时,您的父对象已完全构造。但是,你想要调用任何虚方法,因为它们可以被子类覆盖,当它们没有完全构造时会在其中执行代码。

答案 2 :(得分:7)

一般规则是方法非常简单,不太可能在构造函数中抛出异常。如果方法可能由于任何原因(文件访问或丢失,数据库问题,空引用......)而失败,那么它不应该在构造函数中,因为人们应该期望构造函数不会失败(特别是无参数构造函数,尽管一般指导没有指明)。人们不应期望var seating = new Seating();成为错误的来源。

您可以添加Start() / Initialize()种方法作为您提到的实例方法。您还可以添加一个新的静态方法,该方法在调用您需要的两个方法并返回构造函数私有之后返回Class的新实例。您可以更进一步,在新的Factory类中使用此方法(使构造函数内部)。您也可以考虑其他方法。

有一点是你可以看到在这些方法中计算或检索任何值的构造函数参数(并且没有无参数构造函数),然后构造函数将只将这些参数分配给相应的字段/属性。同一程序集或其他“服务”专用程序集中的工厂方法或服务方法可以负责调用方法,获取参数,将它们传递给构造函数,以及返回类的新实例。这是我个人的最爱。

一般来说,这类问题表明该类做得太多,您可能希望将功能拆分为其他类(现有的或新的)。这就是建议最后一个解决方案的原因,因此这两个方法本身可能位于另一个“服务”程序集中,但如上所述,如果需要,还有许多其他方法可以执行此操作。

更新

以下是Microsoft构造函数指南:
Constructor Usage Guidelines

从页面引用:

  

尽量减少完成的工作量   构造函数。建设者应该   没有做多捕捉   构造函数参数或参数。   这延迟了执行的成本   进一步操作直到用户使用   该实例的特定功能。

更新2

上面的页面移动到一个活文件(这意味着它可以更新),名称为Constructor Design

答案 3 :(得分:6)

一般来说,构造函数应该只设置对象的状态。这可能意味着调用方法。我会说运行很长的方法并不是一个好主意。你的类的用户不希望构造函数成为一种昂贵的方法。

我不是你没有提到虚方法,但你永远不应该在构造函数中调用它们。

以下是一个如何快速恢复的示例:

public class MyBase
{
        protected MyBase()
        {
                this.VirtualMethod();
        }

        protected virtual void VirtualMethod()
        {
                Console.WriteLine("VirtualMethod in MyBase");
        }
}

public class MyDerived : MyBase
{
        private readonly string message = "Set by initializer";

        public MyDerived(string message)
        {
                this.message = message;
        }

        protected override void VirtualMethod()
        {
                Console.WriteLine(this.message);
        }
}

现在,假设您在其他地方使用此代码:

MyDerived d = new MyDerived("Called from constructor");

您认为在控制台上会显示什么?如果您说“由初始化程序设置”,那么您是正确的。

这就是原因:

  • 所有字段初始值设定项都在代码之前执行 构造函数。
  • C#编译器之前添加了对基础构造函数的调用 任何用户定义的东西。在这种情况下,它调用了 调用MyBase的{​​{1}}。自运行时类型为d 是VirtualMethod()MyDerivedVirtualMethod()的覆盖是
    执行。现在因为MyDerived的构造函数的主体没有 执行了,this.message具有在中给出的值 initalizer。
  • 现在执行了MyDerived的构造函数的主体。
  • 此实例的MyDerived稍后调用现在将打印出来 “从构造函数调用”。

答案 4 :(得分:5)

构造函数中的虚方法调用是禁止的(除了密封类的极小例外,这使得该方法实际上是非虚拟的)。

非虚方法可以没问题,但是你应该确保之前已经初始化了所有成员,并且非虚方法也可能不会调用任何虚拟成员。

答案 5 :(得分:2)

这里有一些有用的构造函数设计指南:

  

Constructor Design (MSDN)

案文取消:

  

Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries

这是值得购买的。

多年前我被咬过的那个是:“不要在其构造函数内的对象上调用虚拟成员。”

答案 6 :(得分:0)

您可以随意在其中放置任意数量的代码, 但是按照惯例,开发人员通常希望构造函数做的很少——它的主要工作是确保对象处于有效的初始状态。这可能涉及检查参数并在出现问题时抛出异常,但除此之外别无其他。如果您编写的构造函数执行一些重要的操作,例如将数据添加到数据库或发送 网络消息