1

Here is what I tried but I get this error:

Error CS0029 Cannot implicitly convert type 'ListBoxAndDictionary.CountriesAndCities' to 'System.Collections.Generic.Dictionary<string, System.Collections.Generic.List>'

Here is my code:

private Dictionary<string, List<string>> dictCountryAndCities = new
      Dictionary<string, List<string>>();

private void button12_Click(object sender, EventArgs e)
{
    SaveFileDialog sfd = new SaveFileDialog();
    sfd.FileName = "CountriesAndCities";
    sfd.DefaultExt = ".xml";
    sfd.Filter = "XML (*.xml)|*.xml|All Files (*.*)|*.*";
    var sfdResult = sfd.ShowDialog();
    if (sfdResult == DialogResult.Cancel) 
        return;
    var container = new CountriesAndCities
    {
        DictCountriesAndCities = dictCountryAndCities
    };
    using (var writer = XmlWriter.Create(sfd.FileName)) 
        (new XmlSerializer(typeof(CountriesAndCities))).Serialize(writer, container);
}

private void button11_Click(object sender, EventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.DefaultExt = ".xml";
    ofd.Filter = "XML (*.xml)|*.xml|All Files (*.*)|*.*";
    var ofdResult = ofd.ShowDialog();
    if (ofdResult == DialogResult.Cancel) 
        return;
    dictCountryAndCities = new Dictionary<string, List<string>>();

    XmlSerializer serializer = new XmlSerializer(typeof(CountriesAndCities));
    using (var reader = new StreamReader(ofd.FileName))
    {
        dictCountryAndCities = serializer.Deserialize(reader) as CountriesAndCities;

        //Error CS0029 Cannot implicitly convert type 'ListBoxAndDictionary.CountriesAndCities' to 'System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<string>>'
    }

    //binding DataSource for listBox1
    listBox1.DataSource = dictCountryAndCities.Keys.ToList();
}

[Serializable]
[XmlRoot("CountriesAndCities")]
public class CountriesAndCities
{
    public List<Country> Name
    {
        get { return DictCountriesAndCities.Select(x => new Country { CountryName = x.Key, Cities = x.Value }).ToList(); }
        set { DictCountriesAndCities = value.ToDictionary(x => x.CountryName, x => x.Cities); }
    }
    [XmlIgnore]
    public Dictionary<string, List<string>> DictCountriesAndCities { get; set; }
}

[Serializable]
public class Country
{
    public string CountryName { get; set; }
    public List<string> Cities { get; set; }
}
dbc
  • 104,963
  • 20
  • 228
  • 340
alphabeta
  • 31
  • 6
  • @alphabeta How we can help you if you don't show your xml? – Serge Apr 29 '23 at 16:32
  • There is no problems with deserialization at all. You have simply invalid cast from your custom `CountriesAndCities` class to the `Dictionary>` in the line `dictCountryAndCities = serializer.Deserialize(...)`. You need to provide cast operator or implement data conversion in any other way. – Serg Apr 29 '23 at 16:33
  • 1
    You need to handle dictionaries different than other objects. See : https://stackoverflow.com/questions/3671259/how-to-xml-serialize-a-dictionary – jdweng Apr 29 '23 at 16:37
  • Thanks Serg, but how to do this? Can you give an example? – alphabeta Apr 29 '23 at 16:38
  • @alphabeta Thanks, but the image can not be used. You can past an xml as a text inside of your question. Just click a edit link – Serge Apr 29 '23 at 16:56
  • Why are you serializing a `Dictionary>` when you could easily serialize a `List`? – dbc Apr 29 '23 at 19:00
  • It is about 2 listBoxes. One it display the Keys = Country name and the other it display the Values = Cities name list. See the image in my last comment with the wrong result. In first list I need only the list of keys and in second I need the list of cities linked with country. – alphabeta Apr 29 '23 at 19:36

2 Answers2

0

this code works for me

XDocument doc = XDocument.Load(FILENAME);

Dictionary<string, List<string>> dict = doc.Root.Elements("Country")
                   .ToDictionary(c => (string)c.Element("CountryName"),
                                 c => c.Descendants("Cities").Elements("string")
                   .Select(d => d.Value)
                   .ToList());

you can use this, but I don't see any sense to convert to a dictionary but use only keys.

listBox1.DataSource = dict.Keys.ToList();

this has a little more sense, but not very much too

List<string> source=new List<string>();                              
foreach (var item in dict)
{
        source.Add($"--- {item.Key} ---");
        source.AddRange(item.Value);
}                                
listBox1.DataSource = dict.Keys.ToList();

you need a TreeView user control for a dictionary

Serge
  • 40,935
  • 4
  • 18
  • 45
  • Your code gives error when I try to populate listBox1 with Key. – alphabeta Apr 29 '23 at 17:48
  • @alphabeta Your question is how to deserialize xml to a dictionary. Why should I guess what are you need this data for? I think you cannot use dictionary as a source for a list box. You have to post more details what kind of list box you are trying to create, but you even too lazy to post your xml. How people can help you? There are dozens of different list boxes. YOu have to post the picture how are you to arrange a dictionary to a list? it is very weird. You have at least post ListBoxAndDictionary.CountriesAndCities class – Serge Apr 29 '23 at 18:03
  • I tried many times to post XML as text but I can't because of this message. "It looks like your post is mostly code; please add some more details." – alphabeta Apr 29 '23 at 18:06
  • @alphabeta You must be trying to create a new post. You have to edit the one you published already – Serge Apr 29 '23 at 18:08
  • No, I edit my first post but it is not accepted because of this message. I am new on this forum and I do not understand what to do. English is not my native language, I use Google Translate. – alphabeta Apr 29 '23 at 18:13
  • This seems to work, but something is wrong: var container = new CountriesAndCities() { DictCountriesAndCities = XElement.Load(ofd.FileName).Elements().ToDictionary( x => x.Name.LocalName, x => x.Elements().Select(v => (string)v).ToList()), }; dictCountryAndCities = container.DictCountriesAndCities; //binding DataSource for listBox1 listBox1.DataSource = dictCountryAndCities.Keys.ToList(); https://i.imgur.com/HYdpfkh.png – alphabeta Apr 29 '23 at 18:37
-1

You have a few problems with your XML serialization code.

Firstly, you need to modify your CountriesAndCities DTO as follows, replacing the List<Country> Name surrogate property with a Country [] Name property instead:

[XmlRoot("CountriesAndCities")]
public class CountriesAndCities
{
    public Country [] Name      // Replace the List<Country> with Country []
    {
        get { return DictCountriesAndCities.Select(x => new Country { CountryName = x.Key, Cities = x.Value }).ToArray(); }
        set { DictCountriesAndCities = value?.ToDictionary(x => x.CountryName, x => x.Cities); }
    }
    [XmlIgnore]
    public Dictionary<string, List<string>> DictCountriesAndCities { get; set; }
}

public class Country
{
    public string CountryName { get; set; }
    public List<string> Cities { get; set; }
}

Secondly, modify your serialization code as follows:

var container = new CountriesAndCities
{
    DictCountriesAndCities = dictCountriesAndCities,
};
using (var writer = XmlWriter.Create(sfd.FileName, new XmlWriterSettings { Indent = true })) // Indentation is for visualization purposes only
    (new XmlSerializer(typeof(CountriesAndCities))).Serialize(writer, container);

Finally, change your deserialization code as follows:

using (var reader = new StreamReader(ofd.FileName))
{
    dictCountriesAndCities = ((new XmlSerializer(typeof(CountriesAndCities))).Deserialize(reader) as CountriesAndCities)
        ?.DictCountriesAndCities;
}

Notes:

  • Your "Error CS0029" is caused because you attempt to assign a value of type CountriesAndCities to a Dictionary<string, List<string>>. Instead, you must access the property DictCountriesAndCities.

  • In your method button11_Click() you are deserializing your XML into a local variable dictCountryAndCities, then binding to its keys:

     dictCountryAndCities = new Dictionary<string, List<string>>();
    
     XmlSerializer serializer = new XmlSerializer(typeof(CountriesAndCities));
     using (var reader = new StreamReader(ofd.FileName))
     {
         dictCountryAndCities = serializer.Deserialize(reader) as CountriesAndCities;
    
         //Error CS0029 Cannot implicitly convert type 'ListBoxAndDictionary.CountriesAndCities' to 'System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<string>>'
     }
    

    You are not updating the class member dictCountryAndCities at all. This seems wrong. However, it's not clear from your question what you want to be doing there, so I can't really recommend a fix.

  • The [Serializable] attribute is not required or used by XmlSerializer, and can be removed.

  • For an explanation as to why you should use Country [] instead of List<Country> for your surrogate Name property, see this answer to Cannot deserialize XML into a list using XML Deserializer.

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340