I am trying to determine what issues could be caused by using the following serialization surrogate to enable serialization of anonymous functions/delegate/lambdas.
// see http://msdn.microsoft.com/msdnmag/issues/02/09/net/#S3
class NonSerializableSurrogate : ISerializationSurrogate
{
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
foreach (FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
info.AddValue(f.Name, f.GetValue(obj));
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context,
ISurrogateSelector selector)
{
foreach (FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
f.SetValue(obj, info.GetValue(f.Name, f.FieldType));
return obj;
}
}
Listing 1 adapted from Counting Demo
The main issue I can think of that might be a problem is that the anonymous class is an internal compiler detail and it's structure is not guaranteed to remain constant between revisions to the .NET Framework. I'm fairly certain this is the case based on my research into the similar problem with iterators.
Background
I am investigating the serialization of anonymous functions. I was expecting this not to work, but found it did for some cases. As long as the lambda did *not& force the compiler to generate an anonymous class everything works fine.
A SerializationException is thrown if the compiler requires a generated class to implement the anonymous function. This is because the compiler generated class is not marked as serializable.
Example
namespace Example
{
[Serializable]
class Other
{
public int Value;
}
[Serializable]
class Program
{
static void Main(string[] args)
{
MemoryStream m = new MemoryStream();
BinaryFormatter f = new BinaryFormatter();
// Example 1
Func<int> succeeds = () => 5;
f.Serialize(m, succeeds);
// Example 2
Other o = new Other();
Func<int> fails = () => o.Value;
f.Serialize(m, fails); // throws SerializationException - Type 'Example.Program+<>c__DisplayClass3' in Assembly 'Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
}
}
Listing 2
This is similar to the issue of trying to serialize iterators and I had found the following code in a previous search (see countingdemo) Using the code from Listing 1 and an ISurrogateSelector I was able to successfully serialize and deserialize the second failing example.
Objective
I have a system that is exposed via a web service. The system has a complex but small state (many objects, not a lot of properties per object). The state is saved in the ASP.NET Cache, but is also serialized to a BLOB in SQL in case of cache expiration. Some objects need to execute arbitrary "events" upon reaching some condition. Hence they have properties accepting Action/Func objects. Contrived example:
class Command
{
public Command(Action action, Func<bool> condition);
}
Somewhere else
void DoSomethingWithThing(Thing thing)
{
state = Store.GetCurrentState();
Command cmd = new Command(() => thing.Foo(), () => thing.IsReady())
state.Add(cmd);
Store.Save(state);
}
See Question&Answers more detail:os