I have a class that I want to be serializable but contains a public instance of delegate that, apparently can't be serialized:
<Serializable()> Class A
Public Delegate Function Te开发者_高级运维stEventHandler(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
I used <XmlIgnore()> _
and it helped - i mean the exception is not trowed at this member anymore.
Is there a way to make it serializable however?
Use [XmlIgnore]
on the delegate.
No, there's no way to serialize a delegate. What would it even look like, and what would a platform other than .NET do with it?
You can try using Func<> delegates in 4.0. They are serializable.
And your question is ?
It is quite understandable that a delegate cannot be serialized, since it can be seen as a 'function pointer' rather then real data.
You can solve your problem by applying the NonSerialized
attribute to that delegate.
[Serializable]
public class Test
{
[NonSerialized]
public TestEventHandler TestDelegate;
}
But, remember that Xml Serialization requires other attributes then 'regular' serialization through the BinaryFormatter
or SoapFormatter
classes.
When you use XmlSerialization, you should use the XmlIgnore
attribute.
When you use XmlSerialization, you do not have to mark your class as Serializable
.
Instead, it should have a default public constructor. XmlSerialization only serializes public properties, that have a getter and a setter.
You can control the way your object is serialized via XmlSerialization by these attributes.
You have to store the name of the delegate or method you want to call as a string in the class as well.
I used this as I wanted to configure what function to call after a file has been downloaded via ftp in the config file, i.e. Different ftp download configurations process the downloaded file differently by calling the configured method(delegate).
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; }
Then when you want to use the delegate, in this case after I have downloaded the file. I create the delegate using the string I have stored in the serialized config file.
//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));
}
So ideally you want to store the name of the function/delegate you want to call as a string, and then create it from the string at run time using reflection.
Hope this helps.
Or if the methods to call will only ever exist in the one class you could simplify it by wrapping the properties to simplify it.
//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;
}
}
To really make this configurable it would maybe be an idea to include the Class/Type as well as the function/method name for creating the delegate.
精彩评论