XML-сериализация делегатов - PullRequest
       23

XML-сериализация делегатов

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

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

<Serializable()> Class A
    Public Delegate Function TestEventHandler(ByVal myObj as CutomObject, _
                                         ByVal myObj2 as CustomObject) as Boolean

    ' does not 'want' to be serialized - cause: no parameterless constructor'
    Public TestDelegate as TestEventHandler
End Class

Я использовал <XmlIgnore()> _, и это помогло - я имею в виду, что исключение больше не вызывается для этого участника.

Есть ли способ сделать его сериализуемым, однако?

Ответы [ 4 ]

2 голосов
/ 10 февраля 2010

Используйте [XmlIgnore] для делегата.


Нет, невозможно сериализовать делегата. Как бы это выглядело и что бы с ним делала платформа, отличная от .NET?

2 голосов
/ 08 ноября 2010

Вы можете попробовать использовать Func <> делегаты в 4.0. Они сериализуемы.

1 голос
/ 27 июля 2011

Вы также должны сохранить имя делегата или метода, который вы хотите вызвать, как строку в классе.

Я использовал это, поскольку хотел настроить, какую функцию вызывать после загрузки файла через ftp в файле конфигурации, т. Е. Различные конфигурации загрузки ftp по-разному обрабатывают загруженный файл, вызывая настроенный метод (делегат).

public delegate string ProcessDownloadedFile(string filename);       

        //HACK: Cannot serialise delegates.
        public string ProcessDownloadFileMethod { get; set; }

        //HACK: Cannot serialise delegates.
        [XmlIgnore]
        public ProcessDownloadedFile ProcessFile { get; set; }

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

 //Create the delegate method if it has been set.
 if (!String.IsNullOrEmpty(ftpReceive.ProcessDownloadFileMethod) && ftpReceive.ProcessFile == null)
 {
 //Create the delegate.
 Type t = typeof(FTPTransfer);
 ftpReceive.ProcessFile = (FTPTransfer.ProcessDownloadedFile) Delegate.CreateDelegate(typeof(FTPTransfer.ProcessDownloadedFile), t.GetMethod(ftpReceive.ProcessDownloadFileMethod));
 }

Так что в идеале вы хотите сохранить имя функции / делегата, которую вы хотите вызвать, как строку, а затем создать ее из строки во время выполнения с помощью отражения.

Надеюсь, это поможет.

Или, если вызываемые методы будут когда-либо существовать только в одном классе, вы можете упростить его, обернув свойства, чтобы упростить его.

 //HACK: Cannot serialise delegates.
 public string ProcessDownloadFileMethod { get; set; }

 //HACK: Cannot serialise delegates.
 private ProcessDownloadedFile _processFile;
 [XmlIgnore]
 public ProcessDownloadedFile ProcessFile
 {
   get
   {
     if (_processFile == null && !String.IsNullOrEmpty(ProcessDownloadFileMethod))
     {
        Type t = this.GetType();
        this._processFile = (ProcessDownloadedFile) Delegate.CreateDelegate(typeof(ProcessDownloadedFile), t.GetMethod(this.ProcessDownloadFileMethod));

      }
      return _processFile;
    }
    set
      {
         if (value != null)
         {
            ProcessDownloadFileMethod = value.Method.Name;
         } else {
            ProcessDownloadFileMethod = null;
         }
         _processFile = value;
       }
    }

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

1 голос
/ 10 февраля 2010

А твой вопрос?

Вполне понятно, что делегат не может быть сериализован, поскольку его можно рассматривать как «указатель на функцию», а не как реальные данные.

Вы можете решить свою проблему, применив атрибут NonSerialized к этому делегату.

[Serializable]
public class Test
{
    [NonSerialized]
    public TestEventHandler TestDelegate;
}

Но помните, что для сериализации Xml требуются другие атрибуты, а не «обычная» сериализация через классы BinaryFormatter или SoapFormatter.

Когда вы используете XmlSerialization, вы должны использовать атрибут XmlIgnore. Когда вы используете XmlSerialization, вам не нужно отмечать свой класс как Serializable. Вместо этого он должен иметь открытый конструктор по умолчанию. XmlSerialization сериализует только общедоступные свойства, которые имеют геттер и сеттер.
Вы можете контролировать способ сериализации вашего объекта с помощью этих атрибутов .

...