l-значение требуемой ошибки для оператора сравнения [duplicate]

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

При попытке конвертировать & 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 в свойство «поддержки» первый метод. Таким образом, большая часть ворчания выполняется для вас, но потребители этого класса не подвергаются влиянию, кроме путаницы с интроспекцией.

7
задан Cheok Yan Cheng 9 September 2010 в 08:05
поделиться

5 ответов

Поскольку a :: get_dummy () возвращает неназванный временный объект (int pointer). Объект, возвращаемый функцией, помещает ontop в стек стека, и бессмысленно получить его адрес, поскольку он может быть недействительным после окончания выражения.

4
ответ дан YeenFei 15 August 2018 в 15:14
поделиться
  • 1
    Тот же вопрос, что и ответ Луки. tmp - объект стека! – Billy ONeal 9 September 2010 в 08:22
  • 2
    dummy не является временным объектом или локальным объектом. – Naveen 9 September 2010 в 08:22
  • 3
    @Naveen: Да, это правда. Но ответ не говорит «неназванный временной». (который живет до конца его полного выражения), он говорит «объект стека». который обычно означает объект в «автоматический» который живет до конца его объема. – Billy ONeal 9 September 2010 в 08:23
  • 4
    @Billy, добавили & quot; неназванный & quot; на мой ответ. но я не вижу & quot; стек объекта & quot; в моем ответе, о котором вы говорите. – YeenFei 9 September 2010 в 08:29
  • 5
    @YeenFei: объект стека подразумевается под «верхней частью кадра стека», и "вне области действия". tmp is также недействителен, когда он выходит за пределы области видимости. Без имени компилятора Timeers абсолютно ничего делать с областью. Они живут до конца своего полного выражения. – Billy ONeal 9 September 2010 в 08:33

Какой адрес имел бы me в противном случае? Здесь вы указали ему адрес tmp - но если вы замените его на int ** me = & amp; aa.get_dummy (); , где он будет указывать? [ ! d5]

Нет никакого значимого ответа на этот вопрос, поэтому стандарт требует, чтобы аргумент & amp; был lvalue.

4
ответ дан Billy ONeal 15 August 2018 в 15:14
поделиться
  • 1
    , где бы он указывал? - Не указывает ли он на адрес фиктивного экземпляра? – Cheok Yan Cheng 9 September 2010 в 08:18
  • 2
    @Yan: Нет. Функция возвращает адрес (или значение), хранящийся в манекене , а не фиктивный . – Billy ONeal 9 September 2010 в 08:18
  • 3
    @Yan: Вы можете вернуть фиктивный файл по ссылке, например. INT * & амп; get_dummy. – Puppy 9 September 2010 в 09:13

Вы могли бы определить:

  int ** get_dummy () ... return & amp; dummy;   

Вы можете представить значение r как выражение, по существу, тогда как l-значение является фактическим объектом. Выражения не имеют адресов, и даже если бы они это сделали, трудно представить, какой бы хорошим был адрес. Легко понять, как может быть полезен адрес объекта.

Трудно понять проблему, подобную этой абстрактно. Самый лучший способ развить понимание указателей и скомпилированных языков - изучить язык ассемблера.

7
ответ дан DigitalRoss 15 August 2018 в 15:14
поделиться
  • 1
    +1 для предложения разумного решения проблемы. – Billy ONeal 9 September 2010 в 08:14
  • 2
    У меня нет доступа к исходному коду get_dummy. – Cheok Yan Cheng 9 September 2010 в 08:16
  • 3
    Хм, вы могли бы использовать & amp; aa , но в противном случае, почему вы хотите косвенный указатель? Нет ли API для изменения указателя? Вы даже хотите изменить его? Опасно принимать адрес локальной переменной ... – DigitalRoss 9 September 2010 в 08:21
  • 4
    будь то глобальная, членная или локальная переменная, если ее срок службы превышает реферер, "опасность" висячего указателя не существует. – YeenFei 9 September 2010 в 09:24
  • 5
    @YeenFei, конечно, но возврат локального адреса - это экзотическая операция на любом языке. Когда люди не в полной мере понимают реальность во время выполнения, пребывание на более-очевидно безопасной стороне, вероятно, хорошая идея. – DigitalRoss 12 April 2016 в 00:35

Оператор & должен быть применен к lvalue. Когда вызов aa.get_dummy() не назначен переменной, его возвращаемое значение помещается только в стек, поэтому было бы глупо (и ошибочно) получать адрес элемента стека.

0
ответ дан Luca Martini 15 August 2018 в 15:14
поделиться

Компилятор прав, согласно 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.

0
ответ дан rustyx 15 August 2018 в 15:14
поделиться
Другие вопросы по тегам:

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