【问题标题】:XmlAttribute / XmlElement in Interface (Element Name not changed when Serialized) - Why?接口中的 XmlAttribute / XmlElement(序列化时元素名称未更改) - 为什么?
【发布时间】:2013-02-27 05:19:23
【问题描述】:

当我将“XmlAttribute/XmlElement”添加到接口中的属性并且 100 个其他类从该接口继承时,当将对象序列化为 XML 时 - 为什么我输入的属性名在序列化后没有显示在 XML 文件中?

interface Test
{
    [XmlAttribute("Name")]
    bool PropertyName { get; set; }
}

保存文件时,显示“PropertyName”而不是“Name”。

有没有办法让它工作,所以一个带有 XmlAttributes 添加到接口的属性会更改任何地方的 Value 而不是 Value,因为如果几个类继承自同一个接口,则需要花费大量时间来添加所有这些 Attributes所有继承它的类,更改属性的名称会更容易,而不是更改其中的 100 个。

【问题讨论】:

  • 请不要在标题前加上“C#”之类的前缀。这就是标签的用途。

标签: c# xml interface xml-serialization xml-attribute


【解决方案1】:

Deukalin,花了一些时间使它与类和接口的综合树一起工作。

这是工作代码

    public interface ITestX
    {
        [XmlAttribute("NameX")]
        string PropertyNameX { get; set; }
    }

    public interface ITestY
    {
        [XmlAttribute("NameY")]
        string PropertyNameY { get; set; }
    }

    public interface ITestZ
    {
        [XmlAttribute("NameZ")]
        string PropertyNameZ { get; set; }
    }

    public abstract class TestC : ITestZ
    {
        public abstract string PropertyNameZ { get; set; }
    }

    public abstract class TestA : TestC, ITestX, ITestY
    {
        public abstract string PropertyNameX { get; set; }
        public abstract string PropertyNameY { get; set; }
    }

    public class TestB : TestA
    {
        public override string PropertyNameX { get; set; }
        public override string PropertyNameY  { get; set; }
        public override string PropertyNameZ { get; set; }
    }

    public static class ClassHandler
    {
        public static T GetCustomAttribute<T>(this PropertyInfo propertyInfo, bool inherit) where T : Attribute
        {
            object[] attributes = propertyInfo.GetCustomAttributes(typeof(T), inherit);

            return attributes == null || attributes.Length == 0 ? null : attributes[0] as T;
        }

        public static void GetXmlAttributeOverrides(XmlAttributeOverrides overrides, Type type)
        {
            if (type.BaseType != null)
            {
                GetXmlAttributeOverrides(overrides, type.BaseType);
            }

            foreach (Type derived in type.GetInterfaces())
            {
                foreach (PropertyInfo propertyInfo in derived.GetProperties())
                {
                    XmlAttributeAttribute xmlAttributeAttribute = ClassHandler.GetCustomAttribute<XmlAttributeAttribute>(propertyInfo, true) as XmlAttributeAttribute;

                    if (xmlAttributeAttribute == null)
                        continue;

                    XmlAttributes attr1 = new XmlAttributes();
                    attr1.XmlAttribute = new XmlAttributeAttribute();
                    attr1.XmlAttribute.AttributeName = xmlAttributeAttribute.AttributeName;
                    overrides.Add(type, propertyInfo.Name, attr1);
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            XmlAttributeOverrides XmlAttributeOverrides = new XmlAttributeOverrides();
            ClassHandler.GetXmlAttributeOverrides(XmlAttributeOverrides, typeof(TestB));
            try
            {
                TestB xtest = new TestB() { PropertyNameX = "RajX", PropertyNameY = "RajY", PropertyNameZ = "RajZ" };

                StringBuilder xmlString = new StringBuilder();
                using (XmlWriter xtw = XmlTextWriter.Create(xmlString))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(TestB), XmlAttributeOverrides);
                    serializer.Serialize(xtw, xtest);

                    xtw.Flush();
                }

                Console.WriteLine(xmlString.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
}

下面是上面示例的输出

<?xml version="1.0" encoding="utf-16"?><TestB xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" NameZ="RajZ" Na
meX="RajX" NameY="RajY" />
Press any key to continue . . .

【讨论】:

  • GetXmlAttributeOverrides 是否应该不再返回值?
  • 我将添加我的课程布局。
  • 当我从属性接口实现属性时,我添加了“public bool override PropertyName { get { return _propertyName; } set { _propertyName = value; } }”这给了我错误“没有合适的方法发现要覆盖”,这会是它不取接口 XmlAttribute 值的原因吗?
【解决方案2】:

我更改了代码以更适合我的项目。我所做的是:

    public static XmlAttributeOverrides GetXmlAttributeOverrides(Type type)
    {
        XmlAttributeOverrides overrides = new XmlAttributeOverrides();

        foreach (Type derived in ClassHandler.GetImplementedInterfaces(type))
        {

            foreach (PropertyInfo propertyInfo in derived.GetProperties())
            {
                XmlAttributeAttribute xmlAttributeAttribute = ClassHandler.GetCustomAttribute<XmlAttributeAttribute>(propertyInfo, true) as XmlAttributeAttribute;

                if (xmlAttributeAttribute == null) continue;

                XmlAttributes attr1 = new XmlAttributes();
                attr1.XmlAttribute = new XmlAttributeAttribute();
                attr1.XmlAttribute.AttributeName = xmlAttributeAttribute.AttributeName;
                overrides.Add(type, propertyInfo.Name, attr1);
            }
        }

        return overrides;
    }

我正在尝试实现带有属性的接口的对象都具有“[XmlAttributeAttribute(SomeName)]。

不过,当我对它进行序列化时,它会给出相同的结果。我没有从界面获取属性值。

这就是我序列化的方式:

    public static void SerializeFile(String filename, object obj, bool deleteIfExists = true)
    {

        if (deleteIfExists)
        {
            FileManager.DeleteFile(filename);
        }

        Type[] extraTypes = ClassHandler.GetPropertiesTypes(obj, true);

        using (var stream = new FileStream(filename, FileMode.Create))
        {
            //XmlSerializer xmlSerialize = new XmlSerializer(obj.GetType(), extraTypes); 
            XmlSerializer xmlSerialize = new XmlSerializer(obj.GetType(), GetXmlAttributeOverrides(obj.GetType()), extraTypes, null, null);
            xmlSerialize.Serialize(stream, obj);
        }
    }

我在 ClassHandler 类中使用的两种方法:

    public static T GetCustomAttribute<T>(this PropertyInfo propertyInfo, bool inherit) where T : Attribute
    {
        object[] attributes = propertyInfo.GetCustomAttributes(typeof(T), inherit);

        return attributes == null || attributes.Length == 0 ? null : attributes[0] as T;
    }

    public static List<Type> GetImplementedInterfaces(Type type)
    {
        Type[] types = type.GetInterfaces();
        List<Type> lTypes = new List<Type>();

        foreach(Type t in types)
        {
            lTypes.Add(t);
        }

        return lTypes;
    }

类具有以下结构:

interface IAnimal
{
    // Properties
    // Methods
}

public abstract class Animal : IAnimal
{
    // Implements IAnimal properties and methods
    // This XmlElement gets written correctly when XML Serializing
    // Example:
    [XmlElement("AnimalAge")]
    public double Age
    {
        get { return _age; }
        set { _age = value; }
    }
}

public abstract class Bird : Animal, IAttributeWings
{
    // Implements Attributes common for all "Birds"
    // Setting "override" here gives me error
    public bool HasWings { get { return _hasWings; } set { _hasWings = value; } }
}

public class Pelican : Bird, IAttributeCanFly
{
    // Implements Attributes common for all "Pelicans"
    // Does not implement previous attribute IAttributeWings since Bird class does this
    // Setting "override" here gives me error as well
    public bool CanFly { get { return _canFly; } set { _canFly = value; } }
}

然后属性接口只有“bool CanFly, bool hasWings”之类的属性以及特定类别的此类和其他属性,如本例所示。

【讨论】:

    【解决方案3】:

    它在 .NET 中不起作用的某些原因...但是我想出了这个解决方案来解决您使用 XmlAttributeOverrides 时遇到的问题。有关它的更多信息,请访问以下链接

    http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlattributeoverrides.aspx

    您可以通过在应用程序的某处重构/缓存此 GetXmlAttributeOverrides() 方法来优化它。希望对您有所帮助。

    public interface ITest
    {
        [XmlAttribute("Name")]
        string PropertyName { get; set; }
    }
    
    public class XTest : ITest
    {
        public string PropertyName
        {
            get;
            set;
        }
    }
    
    public class Program
    {
       static void Main(string[] args)
        {
    
            try
            {
                XTest xtest = new XTest() { PropertyName = "Raj" };
    
                StringBuilder xmlString = new StringBuilder();
                using (XmlWriter xtw = XmlTextWriter.Create(xmlString))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(XTest), GetXmlAttributeOverrides(typeof(XTest)));
                    serializer.Serialize(xtw, xtest);
    
                    xtw.Flush();
                }
    
                Console.WriteLine( xmlString.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    
       public static XmlAttributeOverrides GetXmlAttributeOverrides(Type derivedType)
       {
           Type type = typeof(ITest);
           XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    
           XmlAttributes attr = new XmlAttributes();
    
           foreach (PropertyInfo propertyInfo in type.GetProperties())
           {
               XmlAttributeAttribute xmlAttributeAttribute = propertyInfo.GetCustomAttribute(typeof(XmlAttributeAttribute), true) as XmlAttributeAttribute;
    
               if (xmlAttributeAttribute == null) continue;
    
               XmlAttributes attr1 = new XmlAttributes();
               attr1.XmlAttribute = new XmlAttributeAttribute();
               attr1.XmlAttribute.AttributeName = xmlAttributeAttribute.AttributeName;
               overrides.Add(derivedType, propertyInfo.Name, attr1);
           }
    
           return overrides;
       }
    }
    

    编辑:在你的应用程序中包含这个扩展类

    public static class PropertyInfoEx
    {
            public static T GetCustomAttribute<T>(this PropertyInfo propertyInfo, bool inherit) where T : Attribute
            {
                object[] attributes = propertyInfo.GetCustomAttributes(typeof(T), inherit);
    
                return attributes == null || attributes.Length == 0 ? null : attributes[0] as T;
            }
    
    }
    

    【讨论】:

    • 如果我要使用你的方法,是不是我每次创建 XmlAttributeOverride 时都必须指定它实现的交互?因此,使其与以前完全相同。所有对象都实现一个接口,从那里不同类型的类也实现其他接口;所以它不仅仅是一个需要被覆盖的接口,而且每次我想序列化 XML 时,我都必须准确地指定哪些接口。此外,我的程序基于查找实现第一个接口的类,并且我在程序中动态地使用它们。如果我添加一个新类,程序会自动添加它。
    • 我只是得到了快速启动的指导以使其发挥作用。没有开箱即用的东西。您可能需要扩展它以满足您的需求。
    • 另外,会发生这种情况:System.Reflection.PropertyInfo' 不包含“GetCustomAttribute”的定义,并且没有扩展方法“GetCustomAttribute”接受“System.Reflection.PropertyInfo”类型的第一个参数找到(您是否缺少 using 指令或程序集引用?)
    • 请在您的应用中包含 PropertyInfoEx 扩展类。见上文编辑。
    • 我在上面添加了一个新答案(因为它包含我的代码)。请检查我是否遗漏了什么或做错了什么。
    【解决方案4】:

    在您的代码中发现了一些问题。以下是更正后的代码

    public static XmlAttributeOverrides GetXmlAttributeOverrides(Type type)
    {
        XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    
        // Get all interfaces that the "type" implements (is it same as "derivedType" from previously)?
        foreach (Type derived in ClassHandler.GetImplementedInterfaces(type))
        {
    
            foreach (PropertyInfo propertyInfo in derived.GetProperties())
            {
                XmlAttributeAttribute xmlAttributeAttribute = ClassHandler.GetCustomAttribute<XmlAttributeAttribute>(propertyInfo, true) as XmlAttributeAttribute;
    
                if (xmlAttributeAttribute == null) continue;
    
                XmlAttributes attr1 = new XmlAttributes();
                attr1.XmlAttribute = new XmlAttributeAttribute();
                attr1.XmlAttribute.AttributeName = xmlAttributeAttribute.AttributeName;
                overrides.Add(type, propertyInfo.Name, attr1);
            }
        }
    
        return overrides;
    }
    

    自己试试。让我知道它是否有效。

    【讨论】:

    • 还是一样。我将编辑我之前的帖子(使用我的代码版本)并添加获取它实现的接口的类。我从中得到了结果,所以这应该不是问题。
    • A 类 = 实现接口的抽象类, B 类 = 继承 A 类,A 类的一个类别(子类), C 类 = 类别中的一个对象,从那里创建对象。然后,C 类实现唯一的 Attribute 接口,从中获取属性。
    • 请发布您在上面描述的示例类层次结构。
    猜你喜欢
    • 2011-09-17
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多