Это просто неотъемлемое ограничение декларативной сериализации, где информация о типе не встроена в выход.
При попытке конвертировать & 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 экземпляр соответствующего типа * /}}
Это, скорее всего, станет кошмаром для обслуживания ...
Похожие к первому варианту в том, что вы полностью контролируете вещи, но
общедоступный закрытый класс 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 в свойство «поддержки» первый метод. Таким образом, большая часть ворчания выполняется для вас, но потребители этого класса не подвергаются влиянию, кроме путаницы с интроспекцией.
Поскольку a :: get_dummy ()
возвращает неназванный временный объект (int pointer). Объект, возвращаемый функцией, помещает ontop в стек стека, и бессмысленно получить его адрес, поскольку он может быть недействительным после окончания выражения.
№
Какой адрес имел бы me
в противном случае? Здесь вы указали ему адрес tmp
- но если вы замените его на int ** me = & amp; aa.get_dummy ();
, где он будет указывать? [ ! d5]
Нет никакого значимого ответа на этот вопрос, поэтому стандарт требует, чтобы аргумент & amp;
был lvalue.
, где бы он указывал?
- Не указывает ли он на адрес фиктивного экземпляра?
– Cheok Yan Cheng
9 September 2010 в 08:18
манекене
, а не фиктивный
.
– Billy ONeal
9 September 2010 в 08:18
Вы могли бы определить:
int ** get_dummy () ... return & amp; dummy;
Вы можете представить значение r как выражение, по существу, тогда как l-значение является фактическим объектом. Выражения не имеют адресов, и даже если бы они это сделали, трудно представить, какой бы хорошим был адрес. Легко понять, как может быть полезен адрес объекта.
Трудно понять проблему, подобную этой абстрактно. Самый лучший способ развить понимание указателей и скомпилированных языков - изучить язык ассемблера.
& amp; aa
, но в противном случае, почему вы хотите косвенный указатель? Нет ли API для изменения указателя? Вы даже хотите изменить его? Опасно принимать адрес локальной переменной ...
– DigitalRoss
9 September 2010 в 08:21
Оператор &
должен быть применен к lvalue. Когда вызов aa.get_dummy()
не назначен переменной, его возвращаемое значение помещается только в стек, поэтому было бы глупо (и ошибочно) получать адрес элемента стека.
Компилятор прав, согласно ISO C ++ & sect; 5.3.1.3 :
Результат унарного & amp; оператор является указателем на его операнд. Операнд должен быть lvalue или квалифицированным id.
Другими словами, вы можете взять адрес всего, что имеет имя .
Значения, возвращаемые из функций by-value , не имеют имени и часто возвращаются через регистр . Таким образом, нет « address », чтобы говорить о том, что значение не хранится в памяти!
Можно утверждать, что компилятор может быть более умным, обнаружить это и сохранить значение на стек на время выражения, в котором используется адрес. Но это подвержено ошибкам (вы можете «пропустить» указатель на внешнее выражение) и явно будет расширением стандарта (т. Е. Не гарантируется совместимость). Таким образом, MSVC просто запрещает это.
Внимательно, компилятор - это умный , когда дело доходит до ссылки к rvalue. Но для функции нет такой функциональности для rvalue.
Чтобы ответить на ваш вопрос: попытайтесь свести к минимуму адреса адреса; взятие адреса переменной не позволяет оптимизатору перевести его в регистр. Но если вам нужно, верните ссылку:
class a {private: int dummy; public: int get_dummy () const {return dummy; } int & amp; get_dummy () {return dummy; }}; int main () {a aa; int * me = & amp; (aa.get_dummy ()); }
Обратите внимание, что наличие
const get_dummy ()
строго не требуется, но поможет оптимизатору в контекстах rvalue.
tmp
- объект стека! – Billy ONeal 9 September 2010 в 08:22dummy
не является временным объектом или локальным объектом. – Naveen 9 September 2010 в 08:22tmp
is также недействителен, когда он выходит за пределы области видимости. Без имени компилятора Timeers абсолютно ничего i> делать с областью. Они живут до конца своего полного выражения. – Billy ONeal 9 September 2010 в 08:33