2015-05-11 32 views
0

我想创建用最少的代码重复的有效类。链接重载构造

我已经此定义:

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以获取名称并调用最终的构造函数。通过这种方式,所有的执行都应该指向实际执行所有验证等的构造函数之一。其背后的想法是,如果我添加新的构造函数,我只需要提取必要的数据(名字/姓氏)并调用最终的构造函数即可做验证。

然而,有一个编译错误阻止我使用在线Me.New(dt.Rows(0)("FirstName").ToString(),dt.Rows(0)("LastName").ToString())这个系统。显然这条线必须是构造函数中的第一行。但是,如果我将此作为第一行,它将打破验证过程,因为验证将因没有名/姓而引发错误。我必须查询数据库才能获取该信息。

我知道我可以在这里指定的值,并从这个构造函数调用过验证,但是这将有效地从最终一个隔离此构造,从而复制代码,并增加维护了一下。仅供参考,在下面的例子中,我只有2个构造函数,但实际上我还有几个构造函数。如果每个人都能完成自己的任务,那么只需要多加维护。

那么,有没有办法实现通过执行一些代码,然后调用一个重载的构造我的任务是什么?

谢谢你的任何见解

更新1:

每the_lotus评论,我包括DT定义。这个问题有一个解决方法。基本上我会从最终的构造函数中进行验证和赋值,并将其放入函数中。所有的构造函数都会调用这个函数,从而消除链构造函数的需要。它看起来不错,但我想明白为什么要链构造函数,我必须将构造函数调用放在第一行。

这里是新代码:

公共类Foo 私人_FirstName作为字符串= “” 私人_lastName作为字符串= “”

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 

末级

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

+0

你没有显示dt从哪里来。你可以有私有的Initialize方法或者有一个共享的工厂方法。 –

+0

dt在这里不是问题。这就是为什么我包含'查询数据库获取名字和姓氏'代码...我试图保持代码简短。假设我将dt定义为DataTable并查询数据库以获取值。还假设我至少得到一行数据和值。问题出在Me.New上,编译器想把它放在构造函数的第一行。我将用dt更新我的答案定义 – George

+0

是的,您需要有构造函数重载调用遵循您的构造函数声明 - 这是规则。然后,从那里设计你的物体,而不是其他方式。 –

回答

3

你要找一个工厂方法

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 

就个人而言,我不会把数据库里面一个新的。

+1

'就我个人而言,我不会在新的里面调用数据库。过于“忙碌”或者雄心勃勃 – Plutonix

+0

我试图让逻辑变得简单...有人访问我的课程只需要用必要的参数实例化它。错误的机会较少,因为某人不需要实例化,赋值,调用验证等等。从OOP的角度来看,强迫你的类的用户完全按照你想要的去做是有道理的 - 用适当的参数实例化,总是验证,一定要确保该类使用适当的值进行实例化。运行时错误的机会减少,因为有人实例化了我的类,但没有分配正确的值。 – George

+0

这就是说,我对'我不会在新评论中调用数据库'感到困惑。仅仅是因为技术限制还是设计不好?如果是这样,为什么?实质上,解决方案是将DB操作从NEW移动到NEW调用的子操作。我的书中同样的东西。这是一个糟糕的设计吗? – George

0

我不喜欢的事实是,你在构造函数访问数据库,并您在构造函数中进行验证。我将此视为设计问题。下面有3个重载构造函数的例子。所有三个工作。你可能需要#3。使用静态(vb - shared)方法初始化您的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; 
    } 
} 
+0

这个例子对我所遇到的场景来说不是很准确。假设你有一个新的构造函数'public Door(GUID account)',在这个构造函数中,在调用'Door(int locks,int hinges)'之前,你实际上需要查询数据库来获取这些值。它不适用于VB.NET,因为它希望在第一行代码中看到构造函数调用。 – George

+0

@George首先,在构造函数上调用DB永远不是一个好主意。这是你的设计问题。这是你需要理解的。但是如果你想推动你的设计,它仍然是可能的。您可以分开加载逻辑和模型。使用工厂方法“the_lotus”提供或静态对象。我想,我的帖子告诉你,你选择了错误的设计,这就是为什么你在简单情况下遭受的痛苦 –