none
Reading an Xml file into an object via the XmlSerialiser, then doing some more initialization

    Question

  • I can see how the XmlSerializer works, but after reading in the XML into my object I need to do some more initilalization. For example the class may have a filename of an image, but also the bitmap of that image. The bitmap is NOT saved in the XML. So once the filename is read in from the XML I need to read that file to create the bitmap.

    // Create a reader which understands CWholeImageSpec... System.Xml.Serialization.XmlSerializer reader = new System.Xml.Serialization.XmlSerializer(typeof(CWholeImageSpec));

    // Read in the XML file System.IO.StreamReader file = new System.IO.StreamReader( @"C:\LINT\Stuff.XML"); m_ImageSpec = (CWholeImageSpec)reader.Deserialize(file); file.Close(); // Now I want to do more initialization on m_ImageSpec...

    I can do it manually, but maybe there is a method for doing it automatically...if you see what my confused question means.



    http://www.ransen.com Cad and Graphics software


    • Edited by Owen Ransen Friday, February 09, 2018 3:17 PM
    Friday, February 09, 2018 3:16 PM

Answers

  • "I can do it manually, but maybe there is a method for doing it automatically"

    Should also mention that if you wanted to be able to do it without having to update the serialization logic directly then you could also use a calculated property.

    public class CWholeImageSpec
    {
       public string FileName
       {
          get { return _filename ?? ""; }
          set 
          { 
             _filename = value; 
             Image = null;
          }
       }
    
       public Image Image 
       {
          get 
          {
             if (_image == null && !String.IsNullOrEmpty(FileName))
                _image = Image.FromFile(FileName); 
    
             return _image;
          }
          private set 
          {
             if (_image != value)
             {
                //Disposing the image will break anyone
                //currently using it but otherwise you'll
                //leak a resource
                _image?.Dispose();
    
                _image = value;
             };
          }
       }
    
       private Image _image;
       private string _filename;
    }


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Owen Ransen Saturday, February 10, 2018 7:18 AM
    Friday, February 09, 2018 5:43 PM
    Moderator

All replies

  • You're mixing persistence data with business data. Your persistence layer should simply use XML serialization. There is nothing more that it needs to do. The persistence layer should be consumed by your business layer. The business layer would be responsible for loading the data (from persistence) and then doing any additional work to produce the object you want to work with. This would include loading images.

    Michael Taylor http://www.michaeltaylorp3.net

    Friday, February 09, 2018 3:49 PM
    Moderator
  • You're mixing persistence data with business data. Your persistence layer should simply use XML serialization. There is nothing more that it needs to do. The persistence layer should be consumed by your business layer. The business layer would be responsible for loading the data (from persistence) and then doing any additional work to produce the object you want to work with. This would include loading images.

    Michael Taylor http://www.michaeltaylorp3.net

    I've understood the individual words, but not the concepts.

    It seems to me you're less interested in helping me than in showing off your knowledge of the terminology. My question was very specific, you did not answer it.


    http://www.ransen.com Cad and Graphics software

    Friday, February 09, 2018 5:02 PM
  • "It seems to me you're less interested in helping me than in showing off your knowledge of the terminology. My question was very specific, you did not answer it."

    Insulting users in the forums isn't helpful. People posting in the forums are here to help you.  

    I answered your question by indicating that the code you posted is just the persistence side. You don't need to make any more changes to it. The logic you are asking for should be in your business layer which is what consumes the code you posted. Since you didn't provide any of the higher level code it is hard to provide code but here's a very simple example.

    CWholeImageSpecData Load ( string filename )
    {
       //Your posted code goes here with an adjustment to
       //return a lower-level object
    }
    
    //Higher level code that is responsible for loading the data
    void LoadImageSpec ( string filename )
    {
       var data = Load(filename);
    
       //Create and init the business object you actually
       //want to use here
       var image = new CWholeImageSpec(data);
     
       //Do additional initialization here that wasn't covered
    //by serialization image.Image = Image.FromFile(...); m_ImageSpec = image; }

    Could you handle all this in your CWholeImageSpec type? Yes but you'd have to adjust the type to have persistence annotations as well. For example.

    public class CWholeImageSpec
    {
       //Normal stuff
    
       //To store image but it cannot be persisted
       [XmlIgnore]
       public Image Image { get; set; }
    }
    
    //In your load method you can then load the image after deserialization
    m_ImageSpec.Image = Image.FromFile(...);
    The problem with this approach is that your business object now contains XML persistence logic. For a simple app this is fine but if you want to support different formats then it becomes ugly. Hence a data object for persistence and a business object for your code is the preferred route.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, February 09, 2018 5:26 PM
    Moderator
  • "I can do it manually, but maybe there is a method for doing it automatically"

    Should also mention that if you wanted to be able to do it without having to update the serialization logic directly then you could also use a calculated property.

    public class CWholeImageSpec
    {
       public string FileName
       {
          get { return _filename ?? ""; }
          set 
          { 
             _filename = value; 
             Image = null;
          }
       }
    
       public Image Image 
       {
          get 
          {
             if (_image == null && !String.IsNullOrEmpty(FileName))
                _image = Image.FromFile(FileName); 
    
             return _image;
          }
          private set 
          {
             if (_image != value)
             {
                //Disposing the image will break anyone
                //currently using it but otherwise you'll
                //leak a resource
                _image?.Dispose();
    
                _image = value;
             };
          }
       }
    
       private Image _image;
       private string _filename;
    }


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Owen Ransen Saturday, February 10, 2018 7:18 AM
    Friday, February 09, 2018 5:43 PM
    Moderator
  • I'd thought of something like you last answer too. My question was whether there was something like a callback mechanism in the automatic Xml stuff of C#. Seems like there isn't.

    Apologies for the insult. In the past some people DO reply with the simple aim of showing off. Your posts are not like that.


    http://www.ransen.com Cad and Graphics software

    Saturday, February 10, 2018 7:21 AM