Ответ 1
Из Блог Sowmy Srinivasan - Сериализация внутренних типов с помощью XmlSerializer:
Возможность сериализации внутренних типов является одним из распространенных запросов которую видит команда XmlSerializer. Это разумная просьба от людей библиотеки доставки. Они не хотят создавать типы XmlSerializer публично только ради сериализатора. Недавно я перешел из команда, которая написала XmlSerializer для команды, которая потребляет XmlSerializer. Когда я наткнулся на подобную просьбу, я сказал: "Нет. Используйте DataContractSerializer".
Причина проста. XmlSerializer работает, создавая код. сгенерированный код живет в динамически сгенерированной сборке и должен доступ к сериализуемым типам. Поскольку XmlSerializer был разработан за время до появления легкого генерации кода, сгенерированный код не может получить доступ к чему-либо, кроме другой сборке. Следовательно, типы, которые сериализуются, должны быть общедоступными.
Я слышу, как проницательные читатели шепчут: "Это не должно быть публично, если ' InternalsVisibleTo' используется атрибут.
Я говорю: "Правильно, но имя сгенерированной сборки неизвестно авансом. На какую сборку вы делаете внутренности видимыми? "
Астуальные читатели:" имя сборки известно, если вы используете " sgen.exe '"
Me: "Чтобы sgen генерировал сериализатор для ваших типов, они должны быть общественности"
Астуальные читатели: "Мы могли бы сделать компиляцию с двумя проходами. sgen с типами public и другой проход для доставки с типами Внутренности".
Они могут быть правы! Если я попрошу проницательных читателей написать мне образец они, вероятно, напишут что-то вроде этого. (Отказ от ответственности: это а не официальное решение. YMMV)
using System;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.CompilerServices;
using System.Reflection;
[assembly: InternalsVisibleTo("Program.XmlSerializers")]
namespace InternalTypesInXmlSerializer
{
class Program
{
static void Main(string[] args)
{
Address address = new Address();
address.Street = "One Microsoft Way";
address.City = "Redmond";
address.Zip = 98053;
Order order = new Order();
order.BillTo = address;
order.ShipTo = address;
XmlSerializer xmlSerializer = GetSerializer(typeof(Order));
xmlSerializer.Serialize(Console.Out, order);
}
static XmlSerializer GetSerializer(Type type)
{
#if Pass1
return new XmlSerializer(type);
#else
Assembly serializersDll = Assembly.Load("Program.XmlSerializers");
Type xmlSerializerFactoryType = serializersDll.GetType("Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract");
MethodInfo getSerializerMethod = xmlSerializerFactoryType.GetMethod("GetSerializer", BindingFlags.Public | BindingFlags.Instance);
return (XmlSerializer)getSerializerMethod.Invoke(Activator.CreateInstance(xmlSerializerFactoryType), new object[] { type });
#endif
}
}
#if Pass1
public class Address
#else
internal class Address
#endif
{
public string Street;
public string City;
public int Zip;
}
#if Pass1
public class Order
#else
internal class Order
#endif
{
public Address ShipTo;
public Address BillTo;
}
}
Некоторые проницательные "хакерские" читатели могут пойти так далеко, как дать мне build.cmd для его компиляции.
csc /d:Pass1 program.cs
sgen program.exe
csc program.cs