如何轻松确定引用此对象的内容?

时间:2012-09-17 17:58:28

标签: .net serialization reference

我正在尝试实现一种在我的应用程序中克隆元素的方法。这些元素是我自定义和设计的(到目前为止,它们并不是那么复杂)。每个项目都称为Children属性,其中列出了更多实例(将其视为具有多个子分支的树视图)。

我有一个名为“环境”的对象,其中包含对所有这些孩子的引用。把它想象成一个拥有我所有树木的果园。当我想要复制所有内容时,我希望能够在我的“环境”类中调用“clone”并让它为我提供所有内容的副本。

这一切都工作了一段时间,但经过一些更改和代码重构后,它似乎不再起作用,我不知道为什么。我可以很好地遵循堆栈跟踪,但在这种情况下,这是不可能的。这是我的错误的屏幕截图。

enter image description here

我还将使用序列化将我的“环境”实际保存到文件中。然而,在我能够做到这一点之前,我必须将序列化作为一般工作。

无论如何,我已经单独检查了我的单个树/分支/肢体对象,它们都成功克隆了。我似乎无法克隆的唯一东西是“环境”类(我的果园)。这是我的“环境”类的来源:

Imports gE.gEngine
Imports LuaInterface
Imports gE.gEngine.Generic
Imports Microsoft.Xna.Framework
Imports System.Runtime.Serialization
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports gE.gEngine.WorldObjects
Imports System.Windows.Forms
Imports Microsoft.Xna.Framework.Input
Imports System.Threading.Tasks
Imports System.Threading

<Serializable()> _
Public Class Environment

    Public World As WorldServices.World
    Public Players As WorldServices.Players
    Public Lighting As WorldServices.Lighting
    Public Environment As WorldServices.Environment
    Public GenericsLibrary As WorldServices.GenericsLibrary

    <NonSerialized()> _
    Public Lua As New LuaInterface.Lua
    <NonSerialized()> _
    Public SafetyContext As CommonEnum.SafetyContext = CommonEnum.SafetyContext.Safe

    Public Event EnvironmentChanged(ByVal sender As Object, ByVal e As GenericEventArgument)

    Public Sub call_EnvironmentChanged(ByVal sender As Object, ByVal e As GenericEventArgument)
        RaiseEvent EnvironmentChanged(sender, e)
    End Sub

    Public Sub New()
        GlobalShare.Environment = Me
        InitializeLua()

        Lighting = New WorldServices.Lighting()
        World = New WorldServices.World()
        Players = New WorldServices.Players()
        Environment = New WorldServices.Environment()
        GenericsLibrary = New WorldServices.GenericsLibrary()

        Dim ConstraintesGroup As New WorldObjects.Group With {
            .Name = "Constraintes",
            .Parent = GenericsLibrary
        }

        Dim ordsc As List(Of gEngine.WorldObjects.Lua) = Environment.GetScripts()
        ordsc.Sort(Function(x, y) x.RunIndex.CompareTo(y.RunIndex))
        For Each script As gEngine.WorldObjects.Lua In ordsc
            GlobalShare.Environment.RunScript(script.Source, script.Name)
        Next
    End Sub

    Public Sub SetSafetyContext(ByVal e As CommonEnum.SafetyContext)
        If e <> CommonEnum.SafetyContext.Unlocked Then
            SafetyContext = e
            Exit Sub
        End If
        Throw New Exception("Attempt to unlock safety context from unsafe Lua script!")
    End Sub

    Public Sub InitializeLua()
        Lua("Game") = GlobalShare.Game
        Lua("__Environment") = Me
        Lua("gel") = New gELua(Me)
        Lua.RegisterFunction("Print", Lua("gel"), Lua("gel").GetType().GetMethod("Print"))
        Lua.RegisterFunction("print", Lua("gel"), Lua("gel").GetType().GetMethod("Print"))
        Lua.RegisterFunction("SetSafetyContext", Lua("gel"), Me.GetType().GetMethod("SetSafetyContext"))

        Lua("Vector2") = New Lua_.Lua_Vector2
        Lua("Vector3") = New Lua_.Lua_Vector3
        Lua("Mouse") = New Lua_.Lua_Mouse

        Lua.NewTable("Helpers")
        Lua("Helpers.EnumHelper") = New Helpers.EnumHelper

        Dim GameTimer As New Stopwatch
        Lua("Time") = GameTimer
        GameTimer.Start()

        Lua.NewTable("__X")
    End Sub

    Public Function Clone() As Environment
        If [Object].ReferenceEquals(Me, Nothing) Then
            Return Nothing
        End If

        Dim formatter As IFormatter = New BinaryFormatter()
        Dim stream As IO.Stream = New MemoryStream()
        Using stream
            formatter.Serialize(stream, Me)
            stream.Seek(0, SeekOrigin.Begin)
            Return DirectCast(formatter.Deserialize(stream), [Environment])
        End Using
    End Function

    Public Sub RunScript(ByVal scr As String, ByVal name As String)
        Try
            Lua.DoString(scr, name)
        Catch ex As Exception
            Game.CallLogEvent(Me, New GenericEventArgument("LogEvent", "Error", ex.Message))
        End Try
    End Sub

End Class

代码有点凌乱,因为我没有因为这个特殊的问题而对这个特定类很乱(我想知道为什么在我继续改变它之前它不会序列化 - 我不想要在此期间引起更多问题。)

根据错误,它似乎正在尝试序列化我的应用程序窗口(StudioWindow),但是,我在我的应用程序中找不到对它的任何引用。

所以我并不是真的要求你们为我找到参考资料(据我所知,它可能隐藏在我项目的其他部分深处),但我很想找到一种缩小范围的方法问题。我一直在评论部分并试图消除我的项目的某些部分作为问题,但它有点难,因为我的应用程序的某些方面将无法在没有其他部分运行的情况下运行。

感谢任何帮助。如果您想了解更多信息,请询问。我可能会告诉你你要求的任何信息。我的代码主要是VB.NET(虽然,它是一个混合项目,所以很多其他部分都在C#中)所以任何.NET示例/解决方案/帮助都非常受欢迎,同样有用(我可以阅读这两个,所以不要犹豫)。

1 个答案:

答案 0 :(得分:2)

您可以使用不同的选项来阻止订阅者的序列化。它们中的每一个都有优点或缺点。根据您的架构和您的需求:

  1. 使用事件的属性。对于活动,还需要额外的“字段”。在C#中:[field:NonSerialized]。

  2. 将事件设置为null,以在序列化之前删除所有订阅。

  3. 有时将所有数据保存在自己的元素中是一个很好的解决方案。保持此数据对象本身非常简单,易于序列化。如果您这样做,您不必关心所有字段和代表您不想序列化

  4. 实施ISerializable