【问题标题】:XML Object Deserialization to InterfaceXML 对象反序列化到接口
【发布时间】:2010-11-11 20:39:02
【问题描述】:

我有两个类 SccmAction 和 TicketAction,它们都实现了接口 IDelivery。这些类将在处理队列中传输,我只想从中提取消息并根据 Deliver 方法采取行动。

但是,我似乎无法反序列化到接口,因为当我尝试这样做时,会抛出 System.NotSupportedException。从我收集的内容来看,XMLSerializer 需要一个具体的序列化类型。这是否让我不得不创建一个实现 IDelivery 并从中继承 SccmAction 和 ArsAction 的抽象类?我错过了什么吗?

编辑进一步说明

我可能有设计缺陷,但我的目的是从包含这些对象的队列中提取消息。我的意图是让所有来自这个队列的对象都实现接口,确保处理对象的应用程序只在 Deliver 方法上运行。 Deliver 的每个对象实现都会有所不同。

反序列化代码

using (SqlConnection connection =
    new SqlConnection(ConnectionString))
{
    SqlCommand command = new SqlCommand(ReceiveString, connection);
    connection.Open();

    SqlDataReader reader = command.ExecuteReader();

    while (reader.Read())
    {
        byte[] sb = (byte[])reader["message_body"];
        SccmAction sa = DeserializeObject<SccmAction>(sb);
        IDelivery iD = DeserializeObject<IDelivery>(sb);
    }

    reader.Close();
}

public static T DeserializeObject<T>(byte[] ba)
{
    XmlSerializer xs = new XmlSerializer(typeof(T));
    MemoryStream memoryStream = new MemoryStream(ba);
    XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
    return (T)xs.Deserialize(memoryStream);
}

类和接口

[Serializable]
public class SccmAction : IDelivery
{
    public string MachineName { get; set; }
    public string CollectionName { get; set; }
    public string Action { get; set; }
    public DateTime EntryDateTime { get; set; }

    public SccmAction () { }

    public void Deliver()
    {
        throw new NotImplementedException();
    }
}

[Serializable]
public class ArsAction : IDelivery
{
    public string MachineName { get; set; }
    public string CustomerName { get; set; }

    public ArsAction() { }

    public void Deliver()
    {
        throw new NotImplementedException();
    }
}

public interface IDelivery
{
    void Deliver();
}

【问题讨论】:

  • 顺便说一句,XmlSerializer 不需要 [Serializable] 类型 - 后者用于二进制序列化。
  • 没意识到,谢谢你的提示。

标签: c# serialization interface xml-serialization


【解决方案1】:

简单地说,你不能序列化一个没有任何脏东西的接口。但是你为什么要序列化你的接口呢,它不持有任何状态。它只有一个方法的声明。

您可能希望在类中创建一个 Serialize 方法。所以他们可以单独序列化自己,他们知道自己是哪种类型。

此外,您如何期望 XmlSerializer 在不提供确切类型的情况下反序列化?它不能简单地选择反序列化到什么......

但是你可以改变这一行

IDelivery iD = DeserializeObject<IDelivery>(sb);

到这里

IDelivery iD = DeserializeObject<SccmAction>(sb);

如果你不知道你最初反序列化到什么类型(ArsAction 或 SccmAction),那么你可以这样做。

public static IDelivery DeserializeFromString(string xml)
{
      //replace this stream with whatever you are useing
      StringReader strReader = new StringReader(xml);
      XmlReader reader = new XmlTextReader(fs); //important to use XmlReader
      reader.MoveToContent(); //move to root

      String className = reader.Name.Trim(); //read the class name 

      //use the namespace IDelivery is located in
      className  = "IDeliveryNamespace." + className;

      //get the type
      Type classType = Type.GetType(className);

      XmlSerializer serializer = new XmlSerializer(Type.GetType(className));      

      // Declare an object variable of the type to be deserialized.
      IDelivery i;
      // Use the Deserialize method to restore the object's state.
      i = (IDelivery)Convert.ChangeType(serializer.Deserialize(reader),classType);
      return i;
}

当然,这假设您的 Serializable 类名称未更改。意思是 ArsAction 类序列化,据我所知,你发布的情况就是这样。

这段代码有点脏,但它应该给你一个起点。

【讨论】:

  • 当 IDelivery iD = DeserializeObject(sb);会起作用我试图避免知道消息中序列化的类型。
  • @ashteele:我感觉你会这么说。我编辑了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-24
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多