XML 직렬화 가능 클래스에 매개 변수가없는 생성자가 필요한 이유


173

Xml 직렬화를 수행하는 코드를 작성 중입니다. 아래 기능으로.

public static string SerializeToXml(object obj)
{
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
    using (StringWriter writer = new StringWriter())
    {
        serializer.Serialize(writer, obj);
        return writer.ToString();
    }
}

인수가 매개 변수가없는 생성자가없는 클래스의 인스턴스 인 경우 예외가 발생합니다.

처리되지 않은 예외 : System.InvalidOperationException : CSharpConsole.Foo에는 매개 변수가없는 생성자가 없으므로 직렬화 할 수 없습니다. System.Xml.Serialization.ModelScope.GetTypeModel (System.Xml.Serialization.ModelScope.GetTypeModel (System.Xml.Serialization.TypeScope.GetTypeDesc (Type type, MemberInfo sour e, Boolean directReference, Boolean throwOnError))에서 System.Xml.Serialization.ModelScope.GetTypeModel (Type type, System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (Type type, XmlRootAttribute root, String defaultNamespace)의 System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (부울 직접 참조)에서 System.Xml.Serialization의 System.Xml.Serialization.XmlSerializer..ctor (Type type, String defaultName space)입니다. XmlSerializer..ctor (유형)

XML 직렬화가 성공하려면 왜 매개 변수가없는 생성자가 있어야합니까?

편집 : cfeduke의 답변에 감사드립니다. 매개 변수가없는 생성자는 개인용 또는 내부 용일 수 있습니다.


1
관심이 있다면 생성자가 필요없는 객체를 만드는 방법을 찾았습니다 (업데이트 참조). 그러나 이것은 XmlSerializer에 전혀 도움이되지 않습니다-여전히 그것을 요구합니다. 맞춤 코드에 유용합니다.
Marc Gravell

1
XmlSerializer역 직렬화에는 기본 매개 변수없는 생성자가 필요합니다.
Kumar Ghosh를 Amit

답변:


243

객체의 역 직렬화 과정에서 객체의 역 직렬화를 담당하는 클래스는 직렬화 된 클래스의 인스턴스를 만든 다음 인스턴스를 채운 후에 만 ​​직렬화 된 필드와 속성을 채 웁니다.

매개 변수가없는 한 생성자를 만들 private거나 internal원하는 경우 만들 수 있습니다 .


1
그래서 매개 변수가없는 ctor를 개인 또는 내부로 만들 수 있으며 직렬화가 여전히 작동합니다. 답변 주셔서 감사합니다.
Morgan Cheng

2
그렇습니다. 공개 매개 변수가없는 생성자가 제네릭 및 새로운 초기화 구문과 함께 "new ()"를 사용할 수 있기 때문에 자주 사용합니다. 매개 변수가있는 생성자의 경우 정적 팩토리 메소드 또는 빌더 패턴 구현을 사용하십시오.
cfeduke

14
접근성 팁은 좋지만 설명은 직렬화에 적합하지 않습니다. 역 직렬화를 위해서만 객체를 만들어야합니다. 단일 인스턴스를 두 가지 방법으로 사용할 수 있기 때문에 형식 검사 코드가 XmlSerializer 생성자에 내장되어 있다고 생각합니다.
Tomer Gabel

7
@jwg 한 가지 예는 XML을 일종의 웹 서비스에 보내고 자신의 구성 요소에서 해당 객체를받는 데 관심이없는 경우입니다.
Tomer Gabel

5
당신이 당신의 매개 변수가없는 생성자를 만들 경우에도 있다는 사실을 숙지 private하거나 internal, 그 값이 있어야합니다 직렬화 된 당신의 모든 속성 publicsetter를.
chrnola 2016 년

75

의 제한 사항입니다 XmlSerializer. 주의 BinaryFormatterDataContractSerializer 하지 않는 그들이 에테르에서 초기화되지 않은 개체를 만들고 직렬화 복원시를 초기화 할 수 있습니다 -이 필요합니다.

xml을 사용 DataContractSerializer하고 있으므로 클래스를 사용 하고 [DataContract]/ [DataMember]로 표시하는 것을 고려할 수 있지만이 경우 스키마가 변경됩니다 (예를 들어, [XmlAttribute]모든 것이 요소가 됨).

업데이트 : 정말로 알고 싶다면 생성자를 호출하지 않고 객체를 만드는 데 BinaryFormatter사용 FormatterServices.GetUninitializedObject()합니다. 아마 위험하다; 너무 자주 사용하지 않는 것이 좋습니다 ;-p MSDN에 대한 설명도 참조하십시오.

객체의 새 인스턴스가 0으로 초기화되고 생성자가 실행되지 않기 때문에 객체는 해당 객체에 의해 유효한 것으로 간주되는 상태를 나타내지 않을 수 있습니다. 현재 방법은 사용자가 모든 필드를 즉시 채우려는 경우 역 직렬화에만 사용해야합니다. 변경 불가능한 유형의 빈 인스턴스를 작성하는 것은 아무 목적이 없기 때문에 초기화되지 않은 문자열을 작성하지 않습니다.

자신의 직렬화 엔진을 가지고 있지만 그것을 사용하려고하지 않습니다 FormatterServices. 생성자 ( 모든 생성자)가 실제로 실행 되었음을 알고 싶습니다 .


FormatterServices.GetUninitializedObject (Type)에 대한 팁을 주셔서 감사합니다. :)
Omer van Kloeten

6
허; 나는 내 조언을 따르지 않는 것으로 밝혀졌다. protobuf-net은 (선택적으로) 연령대의FormatterServices 사용을 허용했습니다
Marc Gravell

1
그러나 내가 이해하지 못하는 것은 생성자가 지정되지 않은 경우 컴파일러가 매개 변수없는 생성자를 생성한다는 것입니다. 그렇다면 왜 XML 역 직렬화 엔진에 충분하지 않습니까?
toddmo

XML을 역 직렬화하고 생성자를 사용하여 특정 객체를 초기화하려면 (생성자를 통해 요소 / 속성이 제공되도록)이를 달성 할 수있는 방법이 있습니까? 생성자를 사용하여 객체를 빌드하도록 직렬화 프로세스를 사용자 정의하는 방법이 없습니까?
Shimmy Weitzhandler

1
@Shimmy nope; 지원되지 않습니다. 이 있다 IXmlSerializable ,하지만 : 어떻게 그 생성자와 b : 바로 (특히 직렬화)을 얻을 매우 추한 및 하드입니다 - 나는 강하게을 구현하기 위해 노력에 대해 추천 :하지만, 당신이 생성자를 사용하는 것을 허용하지 않습니다
Marc Gravell

4

정답은 : 이유가 없습니다.

이름과 달리 XmlSerializer클래스는 직렬화뿐만 아니라 역 직렬화에도 사용됩니다. 클래스에서 특정 검사를 수행하여 작동하는지 확인하고 일부 검사는 직렬화 해제와 관련이 있지만 나중에 수행하려는 작업을 모르기 때문에 어쨌든 수행합니다.

클래스가 통과하지 못한 확인은 역 직렬화와 관련된 확인 중 하나입니다. 다음과 같은 일이 발생합니다.

  • 역 직렬화 중에 XmlSerializer클래스는 사용자 유형의 인스턴스를 작성해야합니다.

  • 형식의 인스턴스를 만들려면 해당 형식의 생성자를 호출해야합니다.

  • 생성자를 선언하지 않은 경우 컴파일러는 이미 기본 매개 변수없는 생성자를 제공했지만 생성자를 선언 한 경우 사용 가능한 유일한 생성자입니다.

  • 따라서 선언 한 생성자가 매개 변수를 허용하는 경우 클래스를 인스턴스화하는 유일한 방법은 매개 변수를 허용하는 해당 생성자를 호출하는 것입니다.

  • 그러나 XmlSerializer매개 변수가없는 생성자를 제외한 생성자를 호출 할 수는 없습니다. 매개 변수를 허용하는 생성자에 전달할 매개 변수를 모르기 때문입니다. 따라서 클래스에 매개 변수가없는 생성자가 있는지 확인하고 그렇지 않은 경우 실패합니다.

따라서 XmlSerializer클래스가 직렬화와 관련된 검사 만 수행하는 방식으로 작성된 경우 매개 변수가없는 생성자를 가질 필요가있는 직렬화에 대해서는 전혀 없기 때문에 클래스가 전달됩니다.

다른 사람들이 이미 지적했듯이 문제의 빠른 해결책은 단순히 매개 변수가없는 생성자를 추가하는 것입니다. 불행히도 readonly생성자 매개 변수에서 멤버를 초기화 할 수 없기 때문에 더러운 솔루션 입니다.

이 모든 것 외에도 XmlSerializer클래스 매개 변수가없는 생성자가없는 클래스의 직렬화를 해제 할 수있는 방식으로 작성되었을 있습니다. 이 걸릴 것 모두가 사용하게 될 것 "팩토리 메소드 디자인 패턴"(위키 백과) . 외관상으로, Microsoft는 이러한 디자인 패턴이 DotNet 프로그래머에게는 너무 진보되어 있기 때문에 불필요하게 그러한 것들과 혼동해서는 안됩니다. 따라서 Microsoft에 따르면 DotNet 프로그래머는 매개 변수가없는 생성자를 고수해야합니다.


Lol 당신은 말하고, For no good reason whatsoever,계속 말해보십시오 XmlSerializer is not capable of invoking any constructor except a parameterless constructor, because it does not know what parameters to pass to constructors that accept parameters.. 생성자에게 전달할 매개 변수를 모른다면 공장에 전달할 매개 변수를 어떻게 알 수 있습니까? 아니면 어떤 공장을 사용해야합니까? 이 도구를 사용하는 것이 더 간단하다고 상상할 수 없습니다. 직렬 deserialized를 원한 다음 deserializer가 기본 인스턴스를 만든 다음 태그를 지정한 각 필드를 채 웁니다. 쉬운.

0

우선, 이것은 documentation에 쓰여진 것입니다 . 나는 그것이 주요한 분야가 아니라 당신의 계급 분야 중 하나라고 생각합니다-그리고 deserialiser가 어떻게 매개 변수없는 구성없이 그것을 다시 구성하기를 원하십니까?

생성자를 비공개로 만드는 해결 방법이 있다고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.