Сериализация класса, созданного во время выполнения - PullRequest
2 голосов
/ 10 февраля 2012

Я получаю несколько XSD от разных клиентов, и мне нужно предоставить им данные в формате XML в соответствии с предоставленным ими XSD. Я уже написал код для динамического создания и компиляции класса из XSD с использованием codedom, System.Reflection и codeprovider. Теперь я планирую получить данные из базы данных с помощью нескольких запросов, сопоставить поля со свойствами созданного динамического класса и сериализовать их. Я ищу общий способ отображения этих полей, который можно использовать для любого типа xsd, и просто сопоставляя поля, которые он будет сериализовать и дает XML-файл. Что касается запросов, я помещаю их в файл конфигурации. Является ли универсальное решение выполнимым? Любые идеи или указатели о том, как это сделать?

Ответы [ 2 ]

1 голос
/ 15 марта 2012

Мне удалось решить эту проблему. Вот шаги, которые я использовал: я сначала создал сборку во время выполнения из xsd, используя отражение и codedom.compiler с сериализуемыми атрибутами. Используя отражение, я создал экземпляр классов в этой сборке и назначил свойства из данных, полученных из базы данных. Этот класс, который я перенаправил другому методу, который сериализует, берет объект и сериализует его в XML.

Что касается сопоставления, я убедился, что имена столбцов базы данных должны совпадать с именами атрибутов xml, и с этим я смог отобразить и вызвать их.

Вот фрагмент:

object fxClass = myAssembly.CreateInstance(cls.FullName);
Type t = fxClass.GetType();


var arrRates = Array.CreateInstance(t, tab.Rows.Count);
int i =0;
foreach (DataRow dr in tab.Rows)
{
    fxClass = myAssembly.CreateInstance(cls.FullName);
    PropertyInfo[] fxRateProperties = t.GetProperties();
    foreach (PropertyInfo prop in fxRateProperties)
    {
        string rowVal = dr[prop.Name].ToString();

        if (prop.PropertyType == typeof(DateTime))
        {
            prop.SetValue(fxClass, util.convertToDate(rowVal), null);
        }
        else if (prop.PropertyType == typeof(bool))
        {
            prop.SetValue(fxClass, util.convertToBoolean(rowVal), null);
        }
        else if (prop.PropertyType == typeof(decimal))
        {
            prop.SetValue(fxClass, util.convertToDecimal(rowVal), null);
        }
        else prop.SetValue(fxClass, rowVal, null);                                           
    }
    arrRates.SetValue(fxClass,i);
    i++;
}
myClass.GetType().GetProperty("ForexRates").SetValue(myClass, arrRates, null);

Затем передайте объект myClass методу сериализации, который принимает тип объекта, и все

public void serializeXML(object portfolio, string xmlPath)
{
    XmlSerializer serial = new XmlSerializer(portfolio.GetType());
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("", "");
    try
    {
        using (FileStream fs = new FileStream(xmlPath, FileMode.Create, FileAccess.Write))
        {
            using (XmlTextWriter tw = new XmlTextWriter(fs, Encoding.UTF8))
            {
                tw.Formatting = Formatting.Indented;
                serial.Serialize(tw, portfolio, ns);
            }
        }
     }
}

Для этого сейчас я планирую добавить элемент пользовательского интерфейса, в котором сопоставления типа «ForexRates» сохраняются в базе данных, и затем он открывается для любого из типов xsd.

Большое спасибо за ваши ответы.

0 голосов
/ 10 февраля 2012

Вы не можете сериализовать классы, созданные на лету - по крайней мере, не обычным способом.Даже если вы найдете способ присоединить атрибут Serializable, это не даст никакого эффекта: сборка сериализации не будет сгенерирована.

Теоретически вы можете создать совершенно новый класс и создать егово время выполнения, но это было бы абсолютной болью.Если бы вы сделали это, я бы порекомендовал Mono.Cecil вместо стандартного эмиттера IL .NET Framework.

...