【问题标题】:Inheritance casting problem with Generics and XmlSerializer泛型和 XmlSerializer 的继承转换问题
【发布时间】:2009-08-06 16:36:20
【问题描述】:

我如何转换一个对象的实例并真正使它成为那种类型的对象?

我有一个类 myClass1,它是 myClass2 和 myClass3 的基类。我想使用 myClass1 进行审计,我想要的只是来自 myClass1 的数据。因为 myClass2 和 myClass3 从 myClass1 继承,您可以将 myClass1 的实例设置为 myClass2 的实例:

myClass2 foo = new myClass2();
foo.prop1 = "some data";
foo.prop2 = "some More Data";

myClass1 bar = foo;

问题来了是因为我使用的是通用的

 public static IXPathNavigable SerializeGeneric<T>(T serializableObject)
    {
        String XmlizedString = "Error processing request";
        XmlDocument XMLObject = new XmlDocument();
        try
        {
            MemoryStream memoryStream = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(serializableObject.GetType());

在我对其进行序列化时传递类,XmlSerializer 会引发错误,因为即使我已将其转换为 myClass1,基础对象仍然是 myClass2,您可以通过将其转换为对象然后检查类型和 XmlSerializer 来查看这一点很困惑,因为我告诉它让它成为一个 class1 虽然它是自己的反射,但它认为它是一个 myClass2

myClass2 foo = new myClass2();
foo.prop1 = "some data";
foo.prop2 = "some More Data";

myClass1 bar = foo;
object obj = bar;
string name = obj.GetType().Name;

name 的值是“myClass2”,这说明内存中的数据实际上是 myClass2,bar 下方只是指向 myClass2 对象的指针。无需创建新实例并将该新实例的值设置为该对象,例如

myClass1 bar = new myClass1(){prop1=foo.prop1, prop2=foo.prop2};

我真的不想那样做。

【问题讨论】:

  • 你能证明你正在调用 SerializeGeneric 吗?另外,您可能想更改标题,因为我认为 XMLSterilizer 不是您想要的。
  • 是的,XMLSterilizer 会完全不同

标签: c# generics xml-serialization casting


【解决方案1】:

不知道这是否可行,但尝试将其更改为:

XmlSerializer xs = new XmlSerializer(typeof(T));

这将告诉序列化程序创建一个您指定的任何类型的序列化程序实例。虽然我不确定序列化程序是否会这样做。

编辑:只要你打电话

SerializeGeneric<MyClass1>(foo);

再次编辑:

刚刚试了一下:

    public void Test()
    {
        var obj = new Foo2() { Prop1 = "Test", Prop2 = "Test2" };

        SerializeGeneric((Foo1)obj);
    }

    private void SerializeGeneric<T>(T obj)
    {
        StringWriter writer = new StringWriter();    
        XmlSerializer xs = new XmlSerializer(typeof(T));
        xs.Serialize(writer, obj);

        Console.WriteLine(writer.ToString());
    }


    public class Foo1
    {
        public string Prop1 { get; set; }
    }

    public class Foo2 : Foo1
    {
        public string Prop2 { get; set; }
    }

它会引发“意外类型”异常。事实证明,序列化程序不会将对象序列化为不同的类型。不知道有什么办法让它做到这一点。

我想您可以编写一个自定义序列化程序,或者编写一个简单的反射方法,该方法执行一个成员式克隆操作,只从 foo1 复制您想要的属性。

有趣的是,如果将 [XmlInclude(typeof(Foo2))] 添加到 Foo1 声明中,它不会出错,尽管它会输出这种乱码:

<Foo1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Foo2">
  <Prop1>Test</Prop1>
  <Prop2>Test2</Prop2>
</Foo1>

这是一个 Foo1 声明,具有 Foo1 和 Foo2 属性,类型声明为 Foo2...有趣。

最后一个:

这行得通,虽然我不确定我是否会推荐它。

    public void Test ()
    {
        var obj = new Foo2() { Prop1 = "Test", Prop2 = "Test2" };

        SerializeGeneric(ShallowCopy<Foo1>(obj));
    }

    private T ShallowCopy<T>(object input)
        where T : class, new()
    {
        T newObj = Activator.CreateInstance<T>();
        Type oldType = input.GetType();
        BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField | BindingFlags.SetField;
        var oldProperties = oldType.GetProperties(flags);

        foreach (var pd in typeof(T).GetProperties(flags))
        {
            var oldPd = oldProperties.FirstOrDefault(x=>x.Name == pd.Name && x.PropertyType == pd.PropertyType);

            if(oldPd != null)
               pd.SetValue(newObj, oldPd.GetValue(input, null), null);
        }

        return newObj;
    }

这给了你:

<Foo1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Prop1>Test</Prop1>
</Foo1>

看起来很完美。

【讨论】:

  • 我已经尝试过了,是的,你可以这样做,并且由于同样的原因它会出错,通过使用像这样的泛型它将 serializableObject 的类型设置为 T 所以 gettig T 的类型是相同的作为获取序列化对象的类型,
  • 如果您明确声明类型,则不会。
  • 至少我现在感觉不那么糟糕了,因为我不是唯一一个无法解决这个问题的人
  • 甜!!!它起作用了,我不喜欢将我的基类与继承的类结合起来,但在这种情况下,这没什么大不了的
  • 浅拷贝可能更漂亮。
【解决方案2】:

要在继承时正确进行 xml 序列化,有几个准则:

  1. 始终使用typeof(Base) 创建XmlSerializer(在序列化或反序列化时)
  2. 在基类上设置XmlInclude(typeof(Derived)) 属性(对于每个派生类)

这允许您调用反序列化表示继承层次结构中任何对象的任何 xml。还有其他选择(例如将所有可能的派生类型传递给 XmlSerializer 的构造函数,但如果这是对属性的改进,则值得商榷)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-30
    • 2011-08-01
    • 2011-06-14
    • 2011-08-20
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    相关资源
    最近更新 更多