使用泛型与xml反序列化

时间:2012-10-30 09:41:21

标签: c# generics xml-serialization

我想将一个对象传递给xml反序列化的结果类型并保持强类型。

因此,反序列化类可以采用任何实现IResult接口的类型,在本例中为Result和Result2。

我通过使getObject方法返回动态来实现这一点,但我宁愿保持编译时间检查,我认为它应该是可能的。

我尝试过使用泛型,如下例所示,但是deser.getObject(doc()); line给了我一个“无法从使用中推断”的编译错误。

感谢您的帮助。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace SOQuestion
{
    class Program
    {
        static void Main(string[] args)
        {

            var deser = new Deserialised(new Result());
            var result = deser.getObject(doc());

            var deser2 = new Deserialised(new Result2());
            var result2 = deser.getObject(doc());

            Console.Writeline(result.status);
            Console.Writeline(result2.status);
        }

        public XmlDocument doc()
        {
            var doc = new XmlDocument();
            var el = (XmlElement)doc.AppendChild(doc.CreateElement("Result"));
            el.SetAttribute("status", "ok");
            el.SetAttribute("status2", "not ok");
            return doc;

        }

    }

    class Deserialised
    {

        private IResult result;
        private Type resultType;

        public Deserialised(IResult _result)
        {
            result = _result;
            resultType = Type.GetType(result.GetType().AssemblyQualifiedName);
        }


        public T getObject<T>(XmlDocument xml)
        {
            var mySerializer = new XmlSerializer(resultType);
            var myStream = new MemoryStream();
            xml.Save(myStream);
            myStream.Position = 0;
            var r = mySerializer.Deserialize(myStream);
            return (T)r;
        }

    }

    interface IResult
    {
        public string status {get;set;}
    }



    [Serializable]
    public class Result :IResult
    {
        [XmlAttribute]
        public string status { get; set; }
    }

    [Serializable]
    public class Result2 : IResult
    {
        [XmlAttribute]
        public string status2 { get; set; }
    }
}

3 个答案:

答案 0 :(得分:1)

确实,这不会起作用 - 编译器无法从中了解T。请记住,T来自编译时调用者,而不是来自运行时方法的结果。 在反射/泛型之间切换的方法,但它很丑陋,在这里没有多大帮助。我只会返回object

public object GetObject(XmlDocument xml) {
    var mySerializer = new XmlSerializer(resultType);
    using(var myStream = new MemoryStream()) {
        xml.Save(myStream);
        myStream.Position = 0;
        return mySerializer.Deserialize(myStream);
    }
}

然后让调用者处理dynamic等:

var deser = new Deserialised(new Result());
dynamic result = deser.GetObject(doc());

var deser2 = new Deserialised(new Result2());
dynamic result2 = deser.GetObject(doc());

Console.Writeline(result.status);
Console.Writeline(result2.status);

由于上面的dynamic,两个.status中的Console.WriteLine仍然可以使用。

答案 1 :(得分:0)

在我看来the answer you provided yourself使事情过于复杂。 (除了做一些其他奇怪的事情,...看看我的评论。)

在这里使用泛型没有任何好处。您也可以使用以下方法,您的两个要求仍然有效。

public IResult GetObject(XmlDocument xml)
{
    var mySerializer = new XmlSerializer(resultType);
    using (var myStream = new MemoryStream())
    {
        xml.Save(myStream);
        myStream.Position = 0;
        return (IResult)mySerializer.Deserialize(myStream);
    }
}

...只需按以下方式调用:

var deser = new Deserialised(new Result());
var result = (Result)deser.getObject(doc());

var deser2 = new Deserialised(new Result2());
var result2 = (Result2)deser.getObject(doc());

转换为未实现IResult的任何内容都会触发编译器错误。


您在这里尝试做什么并不是很清楚,但假设您Deserialised是通用的。

class Deserialised<T>
    where T : IResult
{

    private T result;
    private Type resultType;

    public Deserialised(T _result)
    {
        result = _result;
    }


    public T getObject(XmlDocument xml)
    {
        var mySerializer = new XmlSerializer(typeof(T));
        var myStream = new MemoryStream();
        xml.Save(myStream);
        myStream.Position = 0;
        var r = (T)mySerializer.Deserialize(myStream);
        return r;
    }

}

为什么你甚至将_result作为参数传递并存储?我的猜测是你只需要它,因为你不知道typeof()?在那种情况下,简单地放弃它。再次这样做之后,您最终会得到一个定义您的泛型参数的类,同样唯一的目的是定义所需的强制转换。

答案 2 :(得分:-1)

所以我找到了一个解决方案,我传递的类型的两个要求实现了IResult接口2.返回的对象是静态类型的。 具有如下约束的通用方法

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace SOQuestion
{
    class Program
    {
        static void Main(string[] args)
        {

            var result = new Deserialised().getObject<Result>();

            var result2 = new Deserialised().getObject<Result2>();

            Console.WriteLine(result.status);
            Console.WriteLine(result.errorMessage);
            Console.ReadLine();


        }
    }

    class Deserialised
    {

        public T getObject<T>() where T : IResult
        {
            try
            {
                var instance = Activator.CreateInstance<T>();
                var mySerializer = new XmlSerializer(instance.GetType());
                var myStream = new MemoryStream();
                doc().Save(myStream);
                myStream.Position = 0;
                var r = mySerializer.Deserialize(myStream);
                throw new DivideByZeroException();
                return (T)r;
            }

            catch (Exception exp)
            {
                var instance = Activator.CreateInstance<T>();
                instance.errorMessage = "something wrong here";
                return instance;
            }
            ;
        }

    public static XmlDocument doc()
        {
            var doc = new XmlDocument();
            var el = (XmlElement)doc.AppendChild(doc.CreateElement("Result"));
            el.SetAttribute("status", "ok");
            el.SetAttribute("status2", "notok");
            return doc;

        }

    }

    interface IResult
    {
        string status { get; set; }
        string errorMessage { get; set; }
    }

    [Serializable]
    public class Result : IResult
    {
        [XmlAttribute]
        public string status { get; set; }

        [XmlAttribute]
        public string errorMessage { get; set; }

        [XmlAttribute]
        public string message { get; set; }
    }

    [Serializable]
    public class Result2 : IResult
    {
        [XmlAttribute]
        public string status { get; set; }

        [XmlAttribute]
        public string message2 { get; set; }

        [XmlAttribute]
        public string errorMessage { get; set; }
    }

    [Serializable]
    public class Result3
    {
        [XmlAttribute]
        public string status { get; set; }

        [XmlAttribute]
        public string message2 { get; set; }

        [XmlAttribute]
        public string errorMessage { get; set; }
    }
}