一个在C#中创建泛型类字典的助手方法

本文关键字:字典 泛型类 方法 创建 一个 | 更新日期: 2023-09-27 18:28:34

我有一个应用程序,其中我有许多从XML文件派生的类(类中的属性名与XML中的节点名匹配),我可以使用反射填充这个类(我在stackoverflow上找到的一些代码经过了适配)。本质上,我枚举XML节点的所有子节点,并尝试在类中获取和设置相应的属性名称。这已经足够好了。虽然我知道XML序列化可能是一个更好的解决方案,但我对我所拥有的一切都很满意。我的问题是如何处理已填充的类。

阅读XML,我会(说)得到200个节点,这些节点转换为给定类的200个实例。我想把这些存进字典里。然后,我将使用另一个XML来生成不同类的100个实例,并且我希望这些实例存储在不同的字典中。

我用来解析XML的代码如下:

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;

正如您所看到的,它具有对特定类类型的特定引用。我希望能够使用一种通用方法,它可以像填充书籍一样轻松地填充DVD和玩具的XML。

有关信息,现有的"MigrateXMLtoObject"例程如下所示:

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);
                }
            }
        }
    }

我考虑过的是让Books、DVD等从一个公共基类继承,但我认为这不会奏效,因为如果我将BaseClass传递给方法,当它试图使用反射来匹配属性时,它们将是基类的属性,而不是派生类的属性。

然后我在这里做了一些搜索,看到了使用泛型的提及。不幸的是,当我使用字典<>时并列出<>对象,我从来没有写过自己的Generic,所以不知道如何使用它们(也不知道这是否真的是我想要的解决方案!)

我确实写了这篇文章,很明显它不起作用/不会编译,但它可能是一个有用的片段,可以让人们把我推向正确的方向:

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;
    }

我是否需要某种"开关"来计算T,并创建相应的基类?

谢谢!

一个在C#中创建泛型类字典的助手方法

如果没有更多的上下文,很难确切知道什么最适合您。但天真的是,我的建议是:

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's 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;
}

你可以这样称呼它:

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

请注意,如果您只是为了传递给对象的构造函数而传递MyLibrary对象,那么在这种方法中,您不需要将其作为方法参数。相反,您可以将其构建到工厂代理中。例如:

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

我还建议您去掉所有前缀为"o"的变量名。这于事无补。:)

我考虑过的事情是让书、DVD等从一个公共基类,但不认为这会起作用,因为如果我通过方法的BaseClass,当它尝试使用反射进行匹配时属性,它们将是基类的属性,而不是派生类。

对不起,你想错了:

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

所以继承是一条路。。