XmlInclude 또는 SoapInclude 특성을 사용하여 정적으로 알려지지 않은 형식을 지정합니다.


98

.NET으로 작업 할 때 매우 이상한 문제가 XmlSerializer있습니다.

다음 예제 클래스를 사용하십시오.

public class Order 
{
    public PaymentCollection Payments { get; set; }

    //everything else is serializable (including other collections of non-abstract types)
}

public class PaymentCollection : Collection<Payment>
{
}

public abstract class Payment 
{
    //abstract methods
}

public class BankPayment : Payment
{
    //method implementations
}

AFAIK, InvalidOperationException파생 된 .NET Framework 형식에 대해 알지 못하는 serializer로 인해 발생하는 문제를 해결하는 세 가지 방법 이 Payment있습니다.

1. 추가 XmlInclude받는 Payment클래스 정의 :

모든 클래스가 내가 제어 할 수없는 외부 참조로 포함되어 있기 때문에 불가능합니다.

2. XmlSerializer인스턴스 생성 중 파생 된 유형의 유형 전달

작동하지 않습니다.

3. XmlAttributeOverrides속성의 기본 직렬화를 재정의하기 위해 대상 속성에 대한 정의 ( 이 SO 게시물에 설명 됨 )

또한 작동하지 않습니다 ( XmlAttributeOverrides초기화가 이어짐).

Type bankPayment = typeof(BankPayment);

XmlAttributes attributes = new XmlAttributes();
attributes.XmlElements.Add(new XmlElementAttribute(bankPayment.Name, bankPayment));

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Order), "Payments", attributes);

XmlSerializer그런 다음 적절한 생성자가 사용됩니다.

참고 : 작동하지 않음InvalidOperationException( BankPayment예상되지 않았습니다 ... )가 발생 한다는 것을 의미합니다 .

누구든지 주제에 대해 밝힐 수 있습니까? 어떻게 문제를 해결하고 디버깅 할 수 있을까요?

답변:


93

이것은 나를 위해 일했습니다.

[XmlInclude(typeof(BankPayment))]
[Serializable]
public abstract class Payment { }    

[Serializable]
public class BankPayment : Payment {} 

[Serializable]
public class Payments : List<Payment>{}

XmlSerializer serializer = new XmlSerializer(typeof(Payments), new Type[]{typeof(Payment)});

15
그렇다면 기본 유형은 모든 구현을 알아야합니까? 이것은별로 좋은 해결책이 아닌 것 같습니다. 다른 방법은 없나요?
Alexander Stolz 2014

2
@AlexanderStolz는 XmlSerializable 객체를 생성하는 동안 새로운 유형을 전달하는 일반 구현을위한 최상의 솔루션입니다. 언급했듯이 stackoverflow.com/a/2689660/698127
Aamol

39

문제를 해결했습니다. 잠시 동안 파헤쳐 본 후 똑같은 상황을 다루는 이 게시물 을 찾았 습니다 . 그것은 나를 올바른 길로 인도했습니다.

기본적으로 파생 클래스가 추가 형식으로 포함 된 경우XmlSerializer 기본 네임 스페이스를 알아야합니다 . 이것이 발생해야하는 정확한 이유는 아직 알려지지 않았지만 여전히 직렬화가 작동하고 있습니다.


2

나는 bizl에 동의합니다

[XmlInclude(typeof(ParentOfTheItem))]
[Serializable]
public abstract class WarningsType{ }

또한이 포함 된 클래스를 개체 항목에 적용해야하는 경우 다음과 같이 할 수 있습니다.

[System.Xml.Serialization.XmlElementAttribute("Warnings", typeof(WarningsType))]
public object[] Items
{
    get
    {
        return this.itemsField;
    }
    set
    {
        this.itemsField = value;
    }
}

1

Base에서 그렇게하면 모든 자식이 직렬화 될 수 있고 코드 정리 코드가 줄어 듭니다.

public abstract class XmlBaseClass  
{
  public virtual string Serialize()
  {
    this.SerializeValidation();

    XmlSerializerNamespaces XmlNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
    XmlWriterSettings XmlSettings = new XmlWriterSettings
    {
      Indent = true,
      OmitXmlDeclaration = true
    };

    StringWriter StringWriter = new StringWriter();

    XmlSerializer Serializer = new XmlSerializer(this.GetType());
    XmlWriter XmlWriter = XmlWriter.Create(StringWriter, XmlSettings);
    Serializer.Serialize(XmlWriter, this, XmlNamespaces);
    StringWriter.Flush();
    StringWriter.Close();

    return StringWriter.ToString();

  }

  protected virtual void SerializeValidation() {}
}

[XmlRoot(ElementName = "MyRoot", Namespace = "MyNamespace")]
public class XmlChildClass : XmlBaseClass
{
  protected override void SerializeValidation()
  {
    //Add custom validation logic here or anything else you need to do
  }
}

이렇게하면 상황에 관계없이 자식 클래스에서 Serialize를 호출 할 수 있으며 개체 Serialize 전에 필요한 작업을 계속 수행 할 수 있습니다.


0

에 기본 나는의 생성자 변경하여이 문제를 해결 할 수 있었다 XmlSerializer사용하는 대신 클래스를 변경했다 I를.

다음과 같은 것을 사용하는 대신 (다른 답변에서 제 안됨) :

[XmlInclude(typeof(Derived))]
public class Base {}

public class Derived : Base {}

public void Serialize()
{
    TextWriter writer = new StreamWriter(SchedulePath);
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>));
    xmlSerializer.Serialize(writer, data);
    writer.Close();
}

나는 이걸했다:

public class Base {}

public class Derived : Base {}

public void Serialize()
{
    TextWriter writer = new StreamWriter(SchedulePath);
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>), new[] { typeof(Derived) });
    xmlSerializer.Serialize(writer, data);
    writer.Close();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.