XmlSerializer требует XmlInclude для открытого метода с общим ограничением, если тип в другой сборке И требует, чтобы этот тип был сериализуемым! - PullRequest
3 голосов
/ 15 сентября 2010

Учтите следующее. У вас есть класс, который вы хотите сериализовать с помощью XmlSerializer, который имеет открытый универсальный метод с ограничением типа, где тип находится в другой сборке:

using BarStuff;

namespace FooStuff {
  public class Foo {
    ...
    public T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
      ...
    }
  }
}

Вы не ожидаете, что XmlSerializer даже будет интересоваться методами, и обычно это не так. Следующие оба прекрасно работают:

//private, serializer doesn't care about it
private T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
  ...
}

//no generic type constraint, serializer also doesn't care about it
public Bar GetBar( string key ) {
  ...
}   

Кроме того, если тип Bar находится в той же сборке, что и Foo, то сериализатор также будет совершенно счастлив.

Когда вы выполните первый пример, если Bar определен в отдельной сборке, вы получите исключение времени выполнения, говорящее о том, что вам нужно добавить ссылку на сборку, содержащую Bar, , даже если у вас уже есть эта сборка в вашем проектные ссылки . Вы можете обойти это, используя XmlInclude:

[XmlInclude(typeof(Bar))]
public class Foo {
  public T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
    ...
  }
}

Однако, если Bar не сериализуем, и нет причин для этого, вы получите исключение времени выполнения при первом обращении к чему-либо, что не может сериализовать, например, открытое свойство, которое возвращает интерфейс в качестве своего. тип, класс без конструктора без параметров и т. д.!

Связано, но не так подробно: XmlSerializer выдает InvalidOperationException при использовании ограничения общего типа, где

Также: Microsoft взяла на себя проблему

1 Ответ

2 голосов
/ 15 сентября 2010

Некоторые обходные пути:

  • Используйте другой сериализатор, такой как DataContractSerializer
  • Убедитесь, что типы находятся в одной сборке, так что XmlInclude не требуется (yuck)
  • Измените Bar, чтобы сделать его сериализуемым (yuck)
  • Избегайте использования методов такого типа, т. е. только сериализации объектов типа DTO и любой такой функциональности в других местах
  • Thisподлый и хакерский ... включает фиктивный класс, который является сериализуемым в той же сборке, что и ваш тип Bar, а затем XmlInclude, который вместо этого сделает сериализатор счастливым, то есть:

Пример:

namespace BarStuff {
  //the serializer is perfectly happy with me
  public class DummyBar{}

  //the serializer doesn't like me
  public class Bar{
  ...
  }

  ...
}

using BarStuff;
namespace FooStuff {
  [XmlInclude(typeof(DummyBar))]
  public class Foo {
    public T GetBar<TBar, T>( string key ) where TBar : Bar<T> {
      ...
    }
  }
...