null when deserializing in C#, works fine in VB.NET

Viewed 142

I am converting a program from VB.NET to C# (And learning C# in the process). I want to convert old binary serialized files into XML or JSON data for the new system, however, when converting in the new C# program, the object is populated to null values. The deserialization works fine in VB.NET. (The type objects are identical)

EDIT: I know BinarySerializer is not the way to go, this is written to read OLD serialized files using the BinarySerializer and convert them to xml.

Working VB Solution:

Type Definition:

<XmlType("GameNfo")>
<Serializable()>
Public Class OldGameNfo
    ' Public Property ImgList As New Collection(Of ImgNfo)
    Public Property Round As New Collection(Of OldRoundNfo)
    Public Property Name As String = ""
    Public Property FileName As String = ""
    <XmlIgnore()> Public Property AnswerRound As Integer = 0
    <XmlIgnore()> Public Property AnswerQuestion As Integer = 0
    <XmlIgnore()> Public Property CurrentRound As Integer = -1
    <XmlIgnore()> Public Property CurrentQuestion As Integer = -1
    <XmlIgnore()> Public Property Completed As Boolean = False
    Public Property Description As String = ""
    <XmlIgnore()> Public Property SelectedRound As Integer = -1
    <XmlIgnore()> Public Property SelectedQuestion As Integer = -1
    Public Property Bonus As New OldBonusNfo
    Public Property Created As New Date(1000, 1, 1)
End Class

<XmlType("BonusNfo")>
<Serializable()> Public Class OldBonusNfo
    Public Property BonusImage As String = ""
    Public Property Question As String = ""
    Public Property Answer As String = ""
    Public Property PointValue As Integer = 0
    Public Property Mosaic As Integer = 0
    Public Property Enabled As Boolean = False
    Public Property WheelPhrase As String = ""
    Public Property WheelCategory As String = ""
    Public Property WheelLetters As String = ""
    Public Property ClueCollection As New Collection(Of String)
    Public Property BonusType As BNType = BNType.None
End Class

<XmlType("RoundNfo")>
<Serializable()> Public Class OldRoundNfo
    Public Property BonusPlacement As Integer = 0
    Public Property Name As String = ""
    Public Property Type As String = ""
    Public Property Category As String = ""
    Public Property Number As Integer = 0
    Public Property Description As String = ""
    Public Property IntroMedia As String = "[DEFAULT]"
    Public Property QuestionIntroMedia As String = "[DEFAULT]"
    Public Property AnswerIntroMedia As String = "[DEFAULT]"
    Public Property QuestionBackMedia As String = "[DEFAULT]"
    Public Property AnswerBackMedia As String = "[DEFAULT]"
    <XmlIgnore()> Public Property Completed As Boolean = False
    Public Property Freeze As Boolean = True
    Public Property Gamble As Boolean = True
    Public Property Lucky As Boolean = True
    Public Property DefaultPointValue As Integer
    Public Property Question As New Collection(Of OldQuestionNfo)
    Public Property Bonus As New OldBonusNfo
End Class

<XmlType("QuestionNfo")>
<Serializable()> Public Class OldQuestionNfo
    Public Property RoundStarted As Boolean = False
    Public Property Created As New Date(1000, 1, 1)
    <XmlIgnore()> Public Property Frozen As Boolean = False
    Public Property Category As String = ""
    Public Property Number As Integer = 0
    Public Property PointValue As Integer = 0
    Public Property Type As String = ""
    Public Property Question As String = ""
    Public Property QuestionAudio As String = ""
    Public Property QuestionImage As String = ""
    Public Property QuestionVideo As String = ""
    Public Property QuestionExtra As String = ""
    Public Property Freeze As Boolean = True
    Public Property Gamble As Boolean = True
    Public Property Lucky As Boolean = True
    Public Property HasBonus As Boolean = False
    Public Property ShowOrder As OrderType = OrderType.QuestionMedia
    Public Property AnswerList As New Collection(Of OldAnswerNfo)
    Public Property Answer As New OldAnswerNfo
    Public Property AnswerAudio As String = ""
    Public Property AnswerImage As String = ""
    Public Property AnswerVideo As String = ""
    Public Property AnswerExtra As String = ""
    <XmlIgnore()> Public Property Asked As Boolean = False
    <XmlIgnore()> Public Property Answered As Boolean = False
    <XmlIgnore()> Public Property Completed As Boolean = False
    Public Property QuestionIntroMedia As String = "[DEFAULT]"
    Public Property AnswerBackMedia As String = "[DEFAULT]"
    Public Property QuestionBackMedia As String = "[DEFAULT]"
    Public Property AnswerIntroMedia As String = "[DEFAULT]"
    Public Property Choices As New Collection(Of String)
    Public Property ID As String = ""
    <XmlIgnore()> Public Property QuestionShown As Boolean = False
    <XmlIgnore()> Public Property AnswerShown As Boolean = False
    <XmlIgnore()> Public Property VideoShown As Boolean = False
    <XmlIgnore()> Public Property AudioShown As Boolean = False
End Class

<XmlType("AnswerNfo")>
<Serializable()> Public Class OldAnswerNfo
    Public Property Answer As String = ""
    Public Property PointValue As Integer = 0
End Class

Code:

    Public Sub ConvertOldGame(ByVal gameDirectory As String)
        Dim GameLoad As OldGameNfo

        Using fs As New FileStream(System.IO.Path.Combine(gameDirectory, "gData.fb"), FileMode.Open)
            Dim formatter As New BinaryFormatter
            formatter.Binder = New Version1ToVersion2DeserializationBinder
            GameLoad = DirectCast(formatter.Deserialize(fs), OldGameNfo)
        End Using
    End Sub

    NotInheritable Class Version1ToVersion2DeserializationBinder
        Inherits SerializationBinder
        Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As System.Type

            Dim typeToDeserialize As System.Type

            typeName = typeName.Replace("GameNfo", "OldGameNfo")
            typeName = typeName.Replace("RoundNfo", "OldRoundNfo")
            typeName = typeName.Replace("BonusNfo", "OldBonusNfo")
            typeName = typeName.Replace("QuestionNfo", "OldQuestionNfo")
            typeName = typeName.Replace("AnswerNfo", "OldAnswerNfo")

            typeToDeserialize = GetType(String.Format("{0}, {1}", typeName, assemblyName))

            Return typeToDeserialize
        End Function
    End Class

Non-working C# version:

Type Definition:

using System;
using System.Collections.Generic;

namespace TriviaBomb.Old
{
   
    [XmlType("GameNfo")]
    [Serializable()]
    public class GameNfo
    {
        // Public Property ImgList As New Collection(Of ImgNfo)
        public Collection<RoundNfo> Round { get; set; } = new Collection<RoundNfo>();
        public string Name { get; set; } = "";
        public string FileName { get; set; } = "";
        [XmlIgnore()]
        public int AnswerRound { get; set; } = 0;
        [XmlIgnore()]
        public int AnswerQuestion { get; set; } = 0;
        [XmlIgnore()]
        public int CurrentRound { get; set; } = -1;
        [XmlIgnore()]
        public int CurrentQuestion { get; set; } = -1;
        [XmlIgnore()]
        public bool Completed { get; set; } = false;
        public string Description { get; set; } = "";
        [XmlIgnore()]
        public int SelectedRound { get; set; } = -1;
        [XmlIgnore()]
        public int SelectedQuestion { get; set; } = -1;
        public BonusNfo Bonus { get; set; } = new BonusNfo();
        public DateTime Created { get; set; } = new DateTime(1000, 1, 1);
    }

    [XmlType("BonusNfo")]
    [Serializable()]
    public class BonusNfo
    {
        public string BonusImage { get; set; } = "";
        public string Question { get; set; } = "";
        public string Answer { get; set; } = "";
        public int PointValue { get; set; } = 0;
        public int Mosaic { get; set; } = 0;
        public bool Enabled { get; set; } = false;
        public string WheelPhrase { get; set; } = "";
        public string WheelCategory { get; set; } = "";
        public string WheelLetters { get; set; } = "";
        public Collection<string> ClueCollection { get; set; } = new Collection<string>();
        public BNType BonusType { get; set; } = BNType.None;
    }

    [XmlType("RoundNfo")]
    [Serializable()]
    public class RoundNfo
    {
        public int BonusPlacement { get; set; } = 0;
        public string Name { get; set; } = "";
        public string Type { get; set; } = "";
        public string Category { get; set; } = "";
        public int Number { get; set; } = 0;
        public string Description { get; set; } = "";
        public string IntroMedia { get; set; } = "[DEFAULT]";
        public string QuestionIntroMedia { get; set; } = "[DEFAULT]";
        public string AnswerIntroMedia { get; set; } = "[DEFAULT]";
        public string QuestionBackMedia { get; set; } = "[DEFAULT]";
        public string AnswerBackMedia { get; set; } = "[DEFAULT]";
        [XmlIgnore()]
        public bool Completed { get; set; } = false;
        public bool Freeze { get; set; } = true;
        public bool Gamble { get; set; } = true;
        public bool Lucky { get; set; } = true;
        public int DefaultPointValue { get; set; }
        public Collection<QuestionNfo> Question { get; set; } = new Collection<QuestionNfo>();
        public BonusNfo Bonus { get; set; } = new BonusNfo();
    }

    [XmlType("QuestionNfo")]
    [Serializable()]
    public class QuestionNfo
    {
        public bool RoundStarted { get; set; } = false;
        public DateTime Created { get; set; } = new DateTime(1000, 1, 1);
        [XmlIgnore()]
        public bool Frozen { get; set; } = false;
        public string Category { get; set; } = "";
        public int Number { get; set; } = 0;
        public int PointValue { get; set; } = 0;
        public string Type { get; set; } = "";
        public string Question { get; set; } = "";
        public string QuestionAudio { get; set; } = "";
        public string QuestionImage { get; set; } = "";
        public string QuestionVideo { get; set; } = "";
        public string QuestionExtra { get; set; } = "";
        public bool Freeze { get; set; } = true;
        public bool Gamble { get; set; } = true;
        public bool Lucky { get; set; } = true;
        public bool HasBonus { get; set; } = false;
        public OrderType ShowOrder { get; set; } = OrderType.QuestionMedia;
        public Collection<AnswerNfo> AnswerList { get; set; } = new Collection<AnswerNfo>();
        public AnswerNfo Answer { get; set; } = new AnswerNfo();
        public string AnswerAudio { get; set; } = "";
        public string AnswerImage { get; set; } = "";
        public string AnswerVideo { get; set; } = "";
        public string AnswerExtra { get; set; } = "";
        [XmlIgnore()]
        public bool Asked { get; set; } = false;
        [XmlIgnore()]
        public bool Answered { get; set; } = false;
        [XmlIgnore()]
        public bool Completed { get; set; } = false;
        public string QuestionIntroMedia { get; set; } = "[DEFAULT]";
        public string AnswerBackMedia { get; set; } = "[DEFAULT]";
        public string QuestionBackMedia { get; set; } = "[DEFAULT]";
        public string AnswerIntroMedia { get; set; } = "[DEFAULT]";
        public Collection<string> Choices { get; set; } = new Collection<string>();
        public string ID { get; set; } = "";
        [XmlIgnore()]
        public bool QuestionShown { get; set; } = false;
        [XmlIgnore()]
        public bool AnswerShown { get; set; } = false;
        [XmlIgnore()]
        public bool VideoShown { get; set; } = false;
        [XmlIgnore()]
        public bool AudioShown { get; set; } = false;
    }

    [XmlType("AnswerNfo")]
    [Serializable()]
    public class AnswerNfo
    {
        public string Answer { get; set; } = "";
        public int PointValue { get; set; } = 0;
    }
}

Code:

        static bool ConvertGame(string sourcePath)
        {
            Old.GameNfo loadGame;
                           
            using System.IO.FileStream fs = new(System.IO.Path.Combine(sourcePath, "gData.fb"), FileMode.Open);
            BinaryFormatter formatter = new();
            formatter.Binder = new Version1ToVersion2DeserializationBinder();
            #pragma warning disable SYSLIB0011 // << Surpress depreciation warning
            loadGame = (Old.GameNfo)formatter.Deserialize(fs);
            
            return returnValue;
        }

        private sealed class Version1ToVersion2DeserializationBinder : SerializationBinder
        {
            public override System.Type BindToType(string assemblyName, string typeName)
            {
                //System.Type typeToDeserialize = null;
                typeName = typeName.Replace("GameNfo", "Old.GameNfo");
                typeName = typeName.Replace("RoundNfo", "Old.RoundNfo");
                typeName = typeName.Replace("BonusNfo", "Old.BonusNfo");
                typeName = typeName.Replace("QuestionNfo", "Old.QuestionNfo");
                typeName = typeName.Replace("AnswerNfo", "Old.AnswerNfo");

                assemblyName = Assembly.GetExecutingAssembly().FullName;
                
                Type typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));

                return typeToDeserialize;
            }
            
        }

To note, this yields the same result whether altering the assemblyName or not in the C# code. Both are TriviaBomb, one is version 0.97, other is 2.0

The namespaces had no effect, same result with keeping in the same namespace (Not .Old as shown in the C# version, kept the OLD version in it's own namespace to preserve object names)

I can't seem to find a solution for days now and I'm hoping it's due to my inexperience in C#.

EDIT: I can verify it is finding the right properties/fields by breaking on the Version1ToVersion2DeserializationBinder class, but no data is being imported. If I change a field name to one that is not in the Object, the operation fails.

0 Answers
Related