Helper method for creating a generic class dictionary in C #

I have an application where I have several classes that I got from XML files (The property names in the class correspond to the node names in XML) and I can populate this class using reflection (some code I found on stackoverflow which I adapted). Basically I am listing all the child XML node and trying to get and set the corresponding property name in my class. This works well enough. While I understand that XML Serialization might be the best solution for this, I am fine with what I have. My question is what I am doing with populated classes.

Reading the XML, I would (say) get 200 nodes that convert to 200 instances of this class. I want to store them in a dictionary. Then I would add another XML to (say) create 100 instances of another class, and I want them to be stored in another dictionary.

The code I am using to parse the XML looks like this:

Dictionary<string, Book> oBookCollection = new Dictionary<string, Book>();
XML_File_Reader oDoc = new XML_File_Reader(@"C:\apps\bookList.xml");
if (oDoc.IsDocumentValid)
{
    XmlNodeList oList = oDoc.GetList("Row");
    if (oList.Count !=0)
    foreach (XmlNode xn in oList)
    {

        XmlNode oThisNode = xn;
        Book oThisBook = new Book(oMyLibrary, oThisNode);

        oDoc.MigrateXMLtoObject(oBuilding, oThisNode);
        oBookCollection .Add(oBook.BookName, oBook);

    }

}
oDoc = null;

      

As you can see, this has specific references to a specific class type. I want to be able to use a generic method that can populate XML for DVDs and toys as easily as for books.

For information, the existing procedure "MigrateXMLtoObject" looks like this:

public void MigrateXMLtoObject(object myObject, XmlNode node)
    {
        if (node == null)
        {
            return;
        }

        PropertyInfo propertyInfo;
        IEnumerator list = node.GetEnumerator();
        XmlNode tempNode;

        while (list.MoveNext())
        {
            tempNode = (XmlNode)list.Current;

            propertyInfo = myObject.GetType().GetProperty(tempNode.Name);


            if (propertyInfo != null)
            {
                if (propertyInfo.PropertyType == typeof(DateTime))
                {
                    DateTime val = DateTime.MinValue;
                    DateTime.TryParse(tempNode.InnerText, out val);
                    propertyInfo.SetValue(myObject, val, null);
                }
                else if (propertyInfo.PropertyType == typeof(Int32))
                {
                    int val = 0;
                    Int32.TryParse(tempNode.InnerText, out val);
                    propertyInfo.SetValue(myObject, val, null);
                }
                else if (propertyInfo.PropertyType == typeof(bool))
                {
                    bool val = false;
                    Boolean.TryParse(tempNode.InnerText, out val);
                    propertyInfo.SetValue(myObject, val, null);
                }
                else if (propertyInfo.PropertyType == typeof(string))
                {
                    string val = "";
                    val = tempNode.InnerText;
                    propertyInfo.SetValue(myObject, val, null);
                }
                else
                {
                    propertyInfo.SetValue(myObject, tempNode.Value, null);
                }
            }

        }
    }

      

What I have reviewed is making books, DVDs, etc. inheriting from a common base class, but I don't think it will work because if I pass the BaseClass to a method when it tries to use reflection to match a property, they will be properties of the base layer, not the derived class.

Then I did some searching here and saw mention of using Generics. Unfortunately, although I use dictionary <> and list <> objects, I have never written my own Generic and therefore do not know how to use them (and this is not actually the solution I am looking for!)

I wrote this and it's clear that it won't work / compile, but this might be a useful snippet for people to nudge me in the right direction:

public Dictionary<string, T> MigrateXMLtoObject<T>(string xmlPath, MyLibrary oLibrary)
    {
        Dictionary<string, T> oDictionary = new Dictionary<string, T>();

        XML_File_Reader oDoc = new XML_File_Reader(xmlPath);
        if (oDoc.IsDocumentValid)
        {
            XmlNodeList oList = oDoc.GetList("Row");
            if (oList.Count != 0)
                foreach (XmlNode xn in oList)
                {

                    XmlNode oThisNode = xn;
                    //T othisItem = new T(oLibrary, oThisNode);

                    oDoc.MigrateXMLtoObject(T, oThisNode);
                    oDictionary.Add(T.Type, T);

                }

        }
        oDoc = null;

        return oDictionary;
    }

      

Do I need some kind of "switch" to evaluate T and create an appropriate base class?

Thank!

+3


source to share


2 answers


Without additional context, it's hard to know exactly what's best for you. But naively, here's what I suggest:

public Dictionary<string, T> MigrateXMLtoObject<T>(
    string xmlPath, MyLibrary oLibrary, Func<MyLibrary, XmlNode, T> factory)
{
    Dictionary<string, T> oDictionary = new Dictionary<string, T>();

    XML_File_Reader oDoc = new XML_File_Reader(xmlPath);
    if (oDoc.IsDocumentValid)
    {
        XmlNodeList oList = oDoc.GetList("Row");
        if (oList.Count != 0)
            foreach (XmlNode xn in oList)
            {

                XmlNode oThisNode = xn;
                T thisItem = factory(oLibrary, oThisNode);

                // It not really clear to me what you wanted to do
                // here. If the object constructor is handling applying
                // the node data to the object, you shouldn't need to
                // "migrate" more, right? And the dictionary seems to
                // want to add the object as the value, with the key
                // being some text. Where do you get the key?
                //oDoc.MigrateXMLtoObject(T, oThisNode);
                oDictionary.Add(objectKey, thisItem);

            }

    }
    oDoc = null;

    return oDictionary;
}

      

If you call it something like this:

MigrateXMLtoObject(xmlPath, library, (l, n) => new Book(l, n));

      



Note that if you are passing an object MyLibrary

only to pass to the object's constructor, then in this approach you don't need it as a method parameter. You can create it in a factory delegate instead. For example:.

MigrateXMLtoObject(xmlPath, node => new Book(library, n));

      

I also suggest that you get rid of all those "o's" prefixed with variable names. It does not help.:)

+1


source


What I've looked at is doing inheritance for books, DVDs, etc. generic base class, but don't think it will work because if I pass the BaseClass to a method when it tries to use reflection to match a property, they will be properties of the base layer, not the derived class.

sorry, but you think it's wrong :( ..



public void SayMyType(BaseClass obj)
{
      Console.Write(obj.GetType())//will output the type of object 'DerivedClass' not the parameter 'BaseClass '
}
SayMyType(new DerivedClass())

      

so inheritance is the way to go.

0


source







All Articles