【问题标题】:Set Object to instance of itself VB.NET将对象设置为自身的实例 VB.NET
【发布时间】:2013-06-08 00:42:51
【问题描述】:

我现在正在使用一个测试对象作为一个非常大的对象(大约 700 个属性)的概念证明。

基本上我要做的是使用新的构造函数设置对象中的数据,而不必手动设置属性,因为有这么多。例如

Person.Name = "Bob"
Person.Age = 30
etc...

相反,我要做的是通过反射遍历对象中的属性并设置对象中的属性。来自大型机的数据以巨大的字符串形式传入......

Private _person As Person

Public Sub New(ByVal personData As String)
    _person = TryCast(ConvertStringToObject(personData, Me.GetType), Person)
End Sub

Public Property FirstName As String
    Get
        Return _person.FirstName
    End Get
    Set(ByVal value As String)
        _person.FirstName = value
    End Set
End Property

 Private Function ConvertStringToObject(ByVal data As String, ByVal obj As Object) As Object

    Dim objectType As Type = obj.GetType
    Dim properties As PropertyInfo() = objectType.GetProperties

    For Each objProperty As PropertyInfo In properties

        'just an example... not really how i get data...
        Dim value As String = data.Substring(0, 10)

        objProperty.SetValue(obj, value, Nothing)

    Next

    Return obj

End Function

因此,当我运行此代码时,一旦设置了属性名(第一个属性),我就会收到一个对象引用集错误...似乎我已经创建了一个悖论...我正在尝试在它存在之前设置一些东西,但要让它存在,我需要先填充它。

我使用的方法需要是通用的,因为它处理的是一堆不同的对象,这就是我返回一个对象的原因。

我过去做过类似的事情,但是实体框架中的实体和实体被构建到 MVC 表单的模型中,但在那种情况下,我有两个不同的对象,所以没有问题。

就目前而言,我的 convertStringToObject 方法自己关闭,我只是调用它并将其转换为我想要的对象,但我真的希望将它放在基类中并让其他对象继承它并使用一个新的构造函数。所以代码看起来像:

dim person as new Person 
person = TryCast(ConvertStringToObject(dataString,person), Person)

同样不是很多代码,但仍然希望通过新的构造函数在类内部进行转换...

任何想法都将不胜感激!

谢谢。

【问题讨论】:

    标签: .net vb.net oop reflection


    【解决方案1】:

    当构建对象是一项复杂或耗时的任务时,我们会应用工厂模式或构建器模式。对于您想要完成的任务,Builder 模式是完美的匹配。 peson 类携带大量数据(对于那 700 个属性)。因此,我们还需要将数据传输与业务模型验证分离。操作方法如下:

    首先解耦数据模型和验证

    Class PersonData
        Public Name as String
        Public Age as integer
        ...
        ...and 700 more...
    End Class
    
    Class person
       private _personData as PersonData = nothing
    
       sub new(personData as PersonData)
           _personData = personData
       end sub
    
       property Name as string
           get
               return _personData.Name
           end get
           set(value as string)
               ...the validations here...
               _personData.Name = value
           end set
        end property
    End Class
    

    然后定义实例化过程

    MustInherit Class PersonBuilder
        protected _stringRepresentation as String
    
        sub setString(stringRep as string)
            _stringRepresentation = stringRep
        end sub
    
        function BuildPerson as Person
    end class
    

    构建具体实例的一种方法是使用大型机中的 loooong 字符串

    class MainFramePersonBuilder
        inherits PesonBuilder
    
        overrides function BuildPerson as Person
             dim pData as PersonData
             pData = DeserializeMainFrameString(_stringRepresentation)
             return new Person(pData)
        end sub
    
        private function DeserializeMainframeString(mString as string) as personData
             ... do the reflection stuff here...
             ... dont use person class direcctly...
             ... rather use the PersonData structure...
    
             return thePersonData
        end sub
    

    另一种方法是使用从某些网络服务获取的数据来做到这一点 我知道它不在范围内,但如果有这个要求,这个架构会有所帮助。

     class JSONPersonBuilder
        inherits PersonBuilder
    
        overrides function BuildPerson as person
            return new Person(DeserializeJSONString(_stringRepresentation))
        end function
    
      end class
    

    所以在你的代码中你可以写

     dim pb as PersonBuilder = new MainFramePersonBuilder() 'JSONPersonBuilder
     pb.setString(mainFrameString) ' JSONString
     dim p as Person = pb.BuildPerson()
    

    现在,如果您需要通过网络或您自己的网络服务将Person 传输到其他地方,则无需发送 mainFrameString。序列化 PersonData 并发送。您将把您的客户端与您的服务器隔离 - 您的 PersonData 是中间层。

    【讨论】:

    • 好的,所以在这种情况下,我复制了 Person 类,其中填充了一个 PersonData 类并将其设置为另一个?我尝试了代码并且它可以工作,但我有点担心开销。不过,这是一种有趣的方法!
    • 编辑了我的帖子以包含我的 ConvertStringToObject 方法当前是如何使用的。
    • 当然会有开销,但是随着我们抽象化的增加,熵确实会增加。这是一个经典的权衡赌注。性能和可维护性。我们正在谈论的代码部分形成业务层并且经常更改。因此,事情需要高度解耦。这个单一的代码很快就会同时暴露在 web-service、sdk-library、web-interface、desktop-interface 等上。 之后发生的事情是一个人出现并要求您将person 与他的Facebook 个人资料整合在一起。与大型机见鬼去吧。顺便说一句,谷歌上 memento-patterndto-pattern
    • 我会看看你提到的其他模式。谢谢你的建议!
    【解决方案2】:

    您已经有了一个可用的变量Me,而不是需要一个私有变量来保存当前的对象实例。以下是调整后的代码,它使用Me 作为设置其属性值的目标:

    Public Sub New(ByVal personData As String)
        ConvertStringToObject(personData)
    End Sub
    
    Public Property FirstName As String
    
     Private Sub ConvertStringToObject(ByVal data As String)
    
        Dim objectType As Type = Me.GetType
        Dim properties As PropertyInfo() = objectType.GetProperties
    
        For Each objProperty As PropertyInfo In properties
    
            'just an example... not really how i get data...
            Dim value As String = data.Substring(0, 10)
    
            objProperty.SetValue(Me, value, Nothing)
    
        Next
    End Function
    

    希望对您有所帮助。

    【讨论】:

    • 我总是对在构造函数中调用复杂的方法持怀疑态度。如果方法抛出异常怎么办?通过反思,很有可能发生这种情况。那么我们有一个未完成的 Person 实例,它处于不一致的状态。在构造函数中调用的方法可能已经将对象引用泄露给其他对象(缓存左右),这样不一致的对象甚至不会被垃圾收集。
    • 这也是一个很好的方法。让一个单独的组件执行复杂对象的构造可以更轻松地交换新的对象创建方式。
    • 嗯,换我而不是私有变量仍然会导致对象引用未设置错误...
    猜你喜欢
    • 2013-01-14
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多