J'essaie de déterminer quels problèmes pourraient être causés par l'utilisation du substitut de sérialisation suivant pour permettre la sérialisation des fonctions/délégations/lambdas anonymes.
// 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;
}
}
Liste 1 adapté de Démonstration de comptage
Le principal problème auquel je peux penser est que la classe anonyme est un détail interne du compilateur et que sa structure n'est pas garantie de rester constante entre les révisions du .NET Framework. Je suis presque certain que c'est le cas, d'après mes recherches sur le problème similaire des itérateurs.
Contexte
J'étudie la sérialisation des fonctions anonymes. Je m'attendais à ce que cela ne fonctionne pas, mais j'ai découvert que cela fonctionnait dans certains cas. Tant que le lambda ne force pas le compilateur à générer une classe anonyme, tout fonctionne bien.
Une SerializationException est levée si le compilateur exige une classe générée pour mettre en œuvre la fonction anonyme. Cela est dû au fait que la classe générée par le compilateur n'est pas marquée comme sérialisable.
Exemple
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.
}
}
Liste 2
C'est similaire au problème d'essayer de sérialiser itérateurs et j'avais trouvé le code suivant lors d'une recherche précédente (voir [countingdemo]) En utilisant le code de Liste 1 et un ISurrogateSelector, j'ai pu sérialiser et désérialiser avec succès le deuxième exemple défaillant.
Objectif
J'ai un système qui est exposé via un service web. Le système a un état complexe mais petit (beaucoup d'objets, pas beaucoup de propriétés par objet). L'état est sauvegardé dans le cache ASP.NET, mais il est également sérialisé en BLOB dans SQL en cas d'expiration du cache. Certains objets doivent exécuter des "événements" arbitraires lorsqu'ils atteignent une certaine condition. Ils ont donc des propriétés acceptant les objets Action/Func. Exemple détourné :
class Command
{
public Command(Action action, Func<bool> condition);
}
Un autre endroit
void DoSomethingWithThing(Thing thing)
{
state = Store.GetCurrentState();
Command cmd = new Command(() => thing.Foo(), () => thing.IsReady())
state.Add(cmd);
Store.Save(state);
}