链接重载的构造函数

Chaining overloaded constructors

我正在尝试创建一个代码重复最少的高效 class。

我有这个定义:

Public Class Foo
    Private _firstName as string = ""
    Private _lastName as string = ""

    Public Sub New(ByVal userGUID As Guid)
        'query DB to get firstName and lastName
        Me.New(dt.Rows(0)("FirstName").ToString(),dt.Rows(0)("LastName").ToString())
    End Sub

    Public Sub New(ByVal firstName As String, ByVal lastName As String)
        _firstName = firstName.toUpper()
        _lastName = lastName.toUpper()
        Validate()
    End Sub

    Private Sub Validate()
        ' Throw error if something is wrong
    End Sub
End Class

带有 firstName 和 lastName 参数的构造函数是进行验证的端点构造函数。以 userGUID 作为参数的构造函数将查询 DB 以获取名称并调用最终构造函数。这样,所有执行都应针对实际执行所有验证等的构造函数之一。其背后的想法是,如果我添加新的构造函数,我只需要提取必要的数据(firstname/lastname)并调用最终的进行验证的构造函数。

但是,有一个编译错误阻止我在 Me.New(dt.Rows(0)("FirstName").ToString(),dt.Rows(0)("LastName").ToString()) 线上使用这个系统。显然这一行必须是构造函数中的第一行。但是如果我把它作为第一行,它会破坏验证过程,因为验证会因没有 firstname/lastname 而抛出错误。我必须查询数据库才能提取该信息。

我知道我可以在这里赋值并从这个构造函数调用验证,但这将有效地将这个构造函数与最后一个构造函数隔离开来,从而重复代码并增加一些维护工作。仅供参考,在下面的示例中我只有 2 个构造函数,但实际上我还有几个。如果每个人都完成自己的任务,那么维护起来就多了。

那么,有没有办法通过执行一些代码然后调用重载的构造函数来完成我的任务?

感谢您的任何见解

更新 1:

根据 the_lotus 评论,我包含了 dt 定义。此问题有一个解决方法。基本上我会从最终构造函数中取出验证和赋值并将其放入函数中。所有构造函数都会调用此函数,因此无需链接构造函数。它看起来不错,但我想了解为什么为了链接构造函数我必须将构造函数调用放在第一行。

这是新代码:

Public Class 富 私有 _firstName 作为字符串 = "" Private _lastName As String = ""

Public Sub New(ByVal userGUID As Guid)
    Dim dt As New DataTable
    ' query DB to get firstName and lastName
    ' Assume I populate dt with at least one DataRow
    AssignAndValidate(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString())
    'Me.New(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString())
End Sub

Public Sub New(ByVal firstName As String, ByVal lastName As String)
    AssignAndValidate(firstName, lastName)
End Sub

Private Sub Validate()
    ' Throw error if something is wrong
End Sub

Private Sub AssignAndValidate(ByVal firstName As String, ByVal lastName As String)
    _firstName = firstName.ToUpper()
    _lastName = lastName.ToUpper()
    Validate()
End Sub

结束Class

一个奇怪的更不用说:在线代码转换器(vb.net 到 C#)在转换链式构造函数调用不在第一行时没有问题。 C# 代码返回为 this.#ctor(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString()); 但是,如果我尝试转换回 VB.NET,它会失败。

我不喜欢的是您在构造函数上访问数据库,并且在构造函数中进行验证。我认为这是设计问题。下面是 3 个重载构造函数的示例。所有三个工作。你可能需要#3。在静态(vb - 共享)方法中初始化你的 dt。您还可以将 fname/lname 参数替换为一个包含这两个参数的参数。这将适用于您的#3

public class A
{
    public A() : this ("xxx")
    {

    }
    public A(string x)
    {

    }
}

public class A
{
    public A() 
    {

    }
    public A(string x): this ()
    {

    }
}

public class A
{
    public A() : this(GetXxx())
    {

    }
    public A(string x)
    {

    }

    private static string GetXxx()
    {
        return "xxx";
    }
}

为什么构造函数链接?因为你的对象可以有很多属性的默认值,而且你可能有很多构造函数,每个都加一个属性。在内部,一个构造函数可以设置 5 个属性,而其他 4 个构造函数只能设置 1 个 属性。

例如:

public class Door
{
    private string _material = "wood";
    private int _locks = 1;
    private int _hinges = 3;

    public Door()
    {

    }
    public Door(int locks) : this()
    {
        _locks = locks;
    }
    public Door(int locks, int hinges) : this(locks)
    {
        _hinges = hinges;
    }
}

你要找的是工厂方法

Public Class Foo 

    Public Shared Function GetFooFromGuid(ByVal userGUID As Guid) As Foo

        ' Query db

        return New Foo(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString())
    End Function

End Class

或者一个初始化函数

Public Class Foo 

    Public Sub New(ByVal userGUID As Guid)
        ' query DB to get firstName and lastName
        Initialize(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString())
    End Sub

    Public Sub New(ByVal firstName As String, ByVal lastName As String)
        Initialize(firstName, lastName)
    End Sub

    Private Sub Initialize(ByVal firstName As String, ByVal lastName As String)
    End Sub

End Class

就个人而言,我不会在 New 中调用数据库。