Как сериализовать свойство интерфейса [duplicate]

Чтобы исключить некоторые данные таблицы, но не структуру таблицы. Вот как я это делаю:

Дамп структуры базы данных всех таблиц без каких-либо данных:

mysqldump -u user -p --no-data database > database_structure.sql

Затем удалите базу данных с данными, за исключением исключенных таблиц, и выполните не сбрасывать структуру:

mysqldump -u user -p --no-create-info \ --ignore-table=database.table1 \ --ignore-table=database.table2 database > database_data.sql

Затем, чтобы загрузить его в новую базу данных:

mysql -u user -p newdatabase < database_structure.sql mysql -u user -p newdatabase < database_data.sql
70
задан Elad 26 August 2009 в 12:13
поделиться

9 ответов

Это просто неотъемлемое ограничение декларативной сериализации, где информация о типе не встроена в выход.

При попытке конвертировать & lt; Flibble Foo = "10" / & gt; назад в

  public class Flibble {public object Foo {get;  задавать;  }}  

Как сериализатор знает, должен ли он быть int, строка, double (или что-то еще) ...

Чтобы сделать эту работу, вы имеют несколько вариантов, но если вы действительно не знаете до выполнения, самый простой способ сделать это, скорее всего, будет использовать XmlAttributeOverrides .

К сожалению, это будет работать только с базовыми классами, а не интерфейсов. Лучшее, что вы можете сделать, это игнорировать свойство, которого недостаточно для ваших нужд.

Если вы действительно должны оставаться с интерфейсами, у вас есть три реальных варианта:

Скрыть его и справиться с ним в другом свойстве

Ужасная, неприятная плита котла и много повторений, но большинству потребителей этого класса не придется решать проблему:

  [XmlIgnore ()  ] общедоступный объект Foo {get;  задавать;  } [XmlElement («Foo»)] [EditorVisibile (EditorVisibility.Advanced)] public string FooSerialized {get {/ * здесь код для преобразования любого типа в Foo в строку * /} set {/ * code для анализа сериализованного значения и make  Foo экземпляр соответствующего типа * /}}  

Это, скорее всего, станет кошмаром для обслуживания ...

Реализовать IXmlSerializable

Похожие к первому варианту в том, что вы полностью контролируете вещи, но

  • Плюсы У вас нет неприятных «поддельных» свойств, висящих вокруг. вы можете напрямую взаимодействовать с структурой xml, добавляя гибкость / управление версиями
  • Минусы, в результате чего вам может потребоваться повторное использование колеса для всех других свойств класса

Измените ваше свойство, чтобы использовать тип упаковки

  общедоступный закрытый класс XmlAnything & lt; T & gt;  : IXmlSerializable {public XmlAnything () {} общедоступный XmlAnything (T t) {this.Value = t;} public T Value {get;  set;} public void WriteXml (XmlWriter writer) {if (Value == null) {writer.WriteAttributeString ("type", "null");  вернуть;  } Тип type = this.Value.GetType ();  XmlSerializer serializer = новый XmlSerializer (тип);  writer.WriteAttributeString ("type", type.AssemblyQualifiedName);  serializer.Serialize (writer, this.Value);  } public void ReadXml (XmlReader reader) {if (! reader.HasAttributes) выдает новое исключение FormatException («ожидается атрибут типа!»);  string type = reader.GetAttribute ("type");  reader.Read ();  // употребляем значение if (type == "null") return; // оставляем T по умолчанию по умолчанию XmlSerializer serializer = new XmlSerializer (Type.GetType (type));  this.Value = (T) serializer.Deserialize (reader);  reader.ReadEndElement ();  } public XmlSchema GetSchema () {return (null);  }}  

Использование этого будет включать в себя что-то вроде (в проекте P):

  public namespace P {public interface IFoo {} public class RealFoo: IFoo {  public int X;  } public class OtherFoo: IFoo {public double X;  } public class Flibble {public XmlAnything & lt; IFoo & gt;  Foo;  } public static void Main (string [] args) {var x = new Flibble ();  x.Foo = новый XmlAnything & lt; IFoo & gt; (новый RealFoo ());  var s = новый XmlSerializer (typeof (Flibble));  var sw = new StringWriter ();  s.Serialize (sw, x);  ЕЫпе (ЕО);  }}  

, который дает вам:

  & lt;? xml version = "1.0" encoding = "utf-16"? & gt;  & lt; MainClass xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns: xsd = "http://www.w3.org/2001/XMLSchema" & gt;  & lt; Foo type = "P.RealFoo, P, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null" & gt;  & Lt; RealFoo & GT;  & Lt; & Х при 0 & л; / Х & GT;  & Lt; / RealFoo & GT;  & Lt; / Foo & GT;  & Lt; / MainClass & GT;   

Это, очевидно, более громоздко для пользователей этого класса, хотя и позволяет избежать большого количества плиты котла.

. Счастливый носитель может объединить идею XmlAnything в свойство «поддержки» первый метод. Таким образом, большая часть ворчания выполняется для вас, но потребители этого класса не подвергаются влиянию, кроме путаницы с интроспекцией.

106
ответ дан Paul George 15 August 2018 в 19:31
поделиться
  • 1
    Я попытался реализовать свой подход к завершающим свойствам, но, к сожалению, у вас есть проблема :( Не могли бы вы посмотреть этот пост, пожалуйста: stackoverflow.com/questions/7584922/… – SOReader 28 September 2011 в 15:38
  • 2
    Есть ли статья, представляющая свойство Foo Serialized? – Gqqnbig 27 July 2013 в 04:37

К несчастью для меня, у меня был случай, когда класс, который должен быть сериализован, имел свойства с интерфейсами как свойствами, поэтому мне нужно было рекурсивно обрабатывать каждое свойство. Кроме того, некоторые свойства интерфейса были отмечены как [XmlIgnore], поэтому я хотел пропустить их. Я взял идеи, которые я нашел в этой теме, и добавил некоторые вещи к ней, чтобы сделать ее рекурсивной. Здесь показан только код десериализации:

  void main () {var serializer = GetDataContractSerializer & lt; MyObjectWithCascadingInterfaces & gt; ();  используя (FileStream stream = новый FileStream (xmlPath, FileMode.Open)) {XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader (поток, новый XmlDictionaryReaderQuotas ());  var obj = (MyObjectWithCascadingInterfaces) serializer.ReadObject (reader);  // ваш код здесь}} DataContractSerializer GetDataContractSerializer & lt; T & gt; (), где T: new () {Тип [] types = GetTypesForInterfaces & lt; T & gt; ();  // Отфильтровать дубликаты Тип [] result = types.ToList (). Distinct (). ToList (). ToArray ();  var obj = new T ();  вернуть новый DataContractSerializer (obj.GetType (), типы);  } Тип [] GetTypesForInterfaces & lt; T & gt; (), где T: new () {return GetTypesForInterfaces (typeof (T));  } Тип [] GetTypesForInterfaces (Тип T) {Тип [] result = new Тип [0];  var obj = Activator.CreateInstance (T);  // получить тип для всех свойств интерфейса, которые не помечены как «XmlIgnore» Type [] types = T.GetProperties () .Where (p = & gt; p.PropertyType.IsInterface & amp;! p.GetCustomAttributes (typeof (  System.Xml.Serialization.XmlIgnoreAttribute), false) .Any ()). Выбрать (p = & gt; p.GetValue (obj, null) .GetType ()) .ToArray ();  result = result.ToList (). Concat (types.ToList ()). ToArray ();  // делаем то же самое для каждого из типов, определенных foreach (тип t в типах) {Type [] embeddedTypes = GetTypesForInterfaces (t);  result = result.ToList (). Concat (embeddedTypes.ToList ()). ToArray ();  } return result;  }  
0
ответ дан acordner 15 August 2018 в 19:31
поделиться

Я нашел более простое решение (вам не нужен DataContractSerializer), благодаря этому блогу здесь: XML-сериализация производных типов, когда базовый тип находится в другом пространстве имен или в DLL

< blockquote>

Но в этой реализации могут подняться две проблемы:

(1) Что делать, если DerivedBase не находится в пространстве имен класса Base или еще хуже в проекте, который зависит от пространства имен Base, поэтому Base не может XMLInclude DerivedBase

(2) Что делать, если у нас есть только класс Base как dll, поэтому Base не может XMLInclude DerivedBase

До сих пор ...

Таким образом, решение двух проблем заключается в использовании XmlSerializer Constructor (Type, array []):

  XmlSerializer ser = new XmlSerializer (typeof (A), новый тип [] {  TypeOf (DerivedBase)});   

Подробный пример представлен здесь в MSDN: XmlSerializer Constructor (Тип, extraTypesArray [])

Мне кажется, что для DataContracts или XML-файлы Soap, вам нужно проверить XmlRoot, как указано здесь в этом вопросе SO .

Аналогичный ответ здесь на SO , но он не является " t отмечен как один, поскольку он, по-видимому, уже не рассматривал ОП.

0
ответ дан B Charles H 15 August 2018 в 19:31
поделиться

Замена интерфейса IModelObject абстрактным или конкретным типом и использование наследования с XMLInclude возможно, но похоже на уродливое обходное решение.

Если можно использовать абстрактный Я бы рекомендовал этот маршрут. Он по-прежнему будет чище, чем использование ручного сериализации. Единственная проблема, которую я вижу с абстрактной базой, заключается в том, что вам все еще нужен конкретный тип? По крайней мере, так я использовал его в прошлом, что-то вроде:

  public abstract class IHaveSomething {public abstract string Something {get;  задавать;  }} public class MySomething: IHaveSomething {string _sometext;  public override string Что-то {get {return _sometext;  } set {_sometext = значение;  }}} [XmlRoot ("abc")] public class seriaized {[XmlElement ("item", typeof (MySomething))] общедоступные данные IHaveSomething;  }  
3
ответ дан Dan Atkinson 15 August 2018 в 19:31
поделиться

Решением этого является использование отражения с помощью DataContractSerializer. Вам даже не нужно отмечать свой класс [DataContract] или [DataMember]. Он будет сериализовать любой объект, независимо от того, имеет ли он свойства типа интерфейса (включая словари) в xml. Вот простой метод расширения, который будет сериализовать любой объект в XML, даже если он имеет интерфейсы (обратите внимание, что вы можете настроить его так же, как и рекурсивно).

  public static XElement ToXML (этот объект o)  {Введите t = o.GetType ();  Тип [] extraTypes = t.GetProperties () .Where (p = & gt; p.PropertyType.IsInterface) .Выберите (p = & gt; p.GetValue (o, null) .GetType ()) .ToArray ();  DataContractSerializer serializer = новый DataContractSerializer (t, extraTypes);  StringWriter sw = new StringWriter ();  XmlTextWriter xw = новый XmlTextWriter (sw);  serializer.WriteObject (xw, o);  return XElement.Parse (sw.ToString ());  }  

, что делает выражение LINQ, перечисляет каждое свойство, возвращает каждое свойство, являющееся интерфейсом, получает значение этого свойства (базового объекта), получает тип этого конкретного объекта помещает его в массив и добавляет это в список известных типов сериализатора.

Теперь сериализатор знает, как о типах, которые он сериализует, чтобы он мог выполнять свою работу.

39
ответ дан Despertar 15 August 2018 в 19:31
поделиться
  • 1
    Очень элегантное и простое решение проблемы. Благодаря! – Ghlouw 27 November 2012 в 12:36
  • 2
    Это, похоже, не работает для общего интерфейса ILIS и интерфейса. например IList & л; IMyInterface & GT ;. Однако значение Concreate для IMyInterface должно быть добавлено в KnownTypes, вместо этого IList & lt; IMyInterface & gt; будет добавлено. – galford13x 26 March 2013 в 21:23
  • 3
    @ galford13x Я попытался сделать этот пример настолько простым, насколько это возможно, все еще демонстрируя точку. Добавление в единичный случай, например, рекурсия или типы интерфейсов, делает его менее понятным для чтения и отнимает от основной точки. Не стесняйтесь добавлять дополнительные проверки, чтобы вытащить нужные известные типы. Честно говоря, я не думаю, что есть что-то, что вы не можете использовать. Это, например, получит тип общего параметра, stackoverflow.com/questions/557340/… – Despertar 26 March 2013 в 23:06
  • 4
    Понимаю, я только упомянул об этом, так как вопрос был задан для сериализации интерфейса. Я решил, что позволю другим узнать, что ошибка будет ожидаться без изменений, чтобы предотвратить удар головой с их стороны. Однако я по достоинству оценил ваш код, так как я добавил атрибут [KnownType ()], и ваш код привел меня к результату. – galford13x 29 March 2013 в 17:56
  • 5
    Есть ли способ зафиксировать пространство имен при сериализации? Я попытался использовать xmlwriterSettings вместо xmlwriter, я использую перегрузку, где я могу передавать дополнительные типы, но он не работает ... – Legends 22 April 2015 в 20:50

в моем проекте, у меня есть List & lt; IFormatStyle & gt; FormatStyleTemplates; содержащие различные типы.

Затем я использую решение «XmlAnything» сверху, чтобы сериализовать этот список разных типов.

  [Browsable (false)] [EditorBrowsable (EditorBrowsableState.Never)] [XmlArray («FormatStyleTemplates»)] [XmlArrayItem («FormatStyle»)] общедоступный XmlAnything & lt; IFormatStyle & gt;  ; [] FormatStyleTemplatesXML {get {return FormatStyleTemplates.Select (t = & gt; новый XmlAnything & lt; IFormatStyle & gt; (t)). ToArray ();  } set {// читаем значения обратно в какой-то новый объект или что-то вроде m_FormatStyleTemplates = new FormatStyleProvider (null, true);  value.ForEach (t = & gt; m_FormatStyleTemplates.Add (t.Value));  }}  
0
ответ дан Detlef Kroll 15 August 2018 в 19:31
поделиться

Если вы знаете, что у вас есть разработчики интерфейса, достаточно простой хак, который вы можете использовать, чтобы получить тип интерфейса для сериализации без написания кода разбора:

  public interface IInterface {} public class  KnownImplementor01: IInterface {} public class KnownImplementor02: IInterface {} public class KnownImplementor03: IInterface {} public class ToSerialize {[XmlIgnore] public IInterface InterfaceProperty {get;  задавать;  } [XmlArray («интерфейс»)] [XmlArrayItem («ofTypeKnownImplementor01», typeof (KnownImplementor01)] [XmlArrayItem («ofTypeKnownImplementor02», typeof (KnownImplementor02)] [XmlArrayItem («ofTypeKnownImplementor03», typeof (KnownImplementor03)] public object [] InterfacePropertySerialization  {get {return new [] {InterfaceProperty}} set {InterfaceProperty = (IInterface) value.Single ();}}}  

Получившийся xml должен выглядеть примерно так:

  & lt; interface & gt; & lt; ofTypeKnownImplementor01 & gt; & lt;! - etc ... - & gt;  
4
ответ дан hannasm 15 August 2018 в 19:31
поделиться
  • 1
    Очень полезно, спасибо. В большинстве случаев я знаю классы, реализующие интерфейс. Этот ответ должен быть выше imo. – Jonah 12 March 2018 в 12:34

К сожалению, нет простого ответа, поскольку сериализатор не знает, что сериализовать для интерфейса. Я нашел более полное объяснение того, как обходиться это на MSDN

2
ответ дан MattH 15 August 2018 в 19:31
поделиться

Вы можете использовать ExtendedXmlSerializer . Этот сериализатор поддерживает сериализацию свойства интерфейса без каких-либо трюков.

  var serializer = new ConfigurationContainer (). UseOptimizedNamespaces (). Create ();  var obj = new Пример {Model = new Model {Name = "name"}};  var xml = serializer.Serialize (obj);   

Ваш xml будет выглядеть так:

  & lt;? xml version = "1.0" encoding = "utf-8"? & gt;  & lt; Пример xmlns: exs = "https://extendedxmlserializer.github.io/v2" xmlns = "clr-namespace: ExtendedXmlSerializer.Samples.Simple; assembly = ExtendedXmlSerializer.Samples" & gt;  & lt; Модель exs: type = "Model" & gt;  & Lt; & Имя GT; имя & л; / Имя & GT;  & Lt; / Модель & GT;  & Lt; / Пример & GT;   

ExtendedXmlSerializer поддерживает .net 4.5 и .net Core.

5
ответ дан Wojtpl2 15 August 2018 в 19:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: