While other questions about using reflection to bypass all safeties and directly call the base class's implementation of an overridden method have generally been met with derision and calls to redesign the offending code, I think I've stumbled upon a bizarre but legitimate use case: delegate serialization. Since I've seen the other questions, please don't bombard me with advice to redesign my code and stop trying to bypass the type system -- I'm writing a serialization formatter, and those already get a pass to ignore constructors.
Much to my dismay, even the v2.0 BCL's BinaryFormatter
fails this simple NUnit test:
[TestFixture]
public class DelegateSerializationTestFixture
{
[Test]
public void DelegateSerializationTest()
{
var bigKitty = new Lion();
var kittyNoise = bigKitty.GetKittyNoiseFunc();
Assert.AreEqual("Meow", kittyNoise());
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, kittyNoise);
stream.Position = 0;
formatter = new BinaryFormatter();
var kittyNoise2 = (Func<string>)formatter.Deserialize(stream);
Assert.AreEqual("Meow", kittyNoise2()); // returns Grrr
}
}
[Serializable]
public class Lion : Cat
{
public override string GetNoise()
{
return "Grrr";
}
public Func<string> GetKittyNoiseFunc()
{
return base.GetNoise;
}
}
[Serializable]
public class Cat
{
public virtual string GetNoise()
{
return "Meow";
}
}
If BinaryFormatter
itself can't get this right, I guess I shouldn't be surprised that my own Compact Framework 3.5 binary serialization implementation drops the ball as well.
If it's truly impossible to reconstruct such a delegate using only the Compact Framework v3.5's limited reflection capabilities -- and it may well be -- is there a way to at least detect such a delegate so that my serializer can throw instead of leaving incorrect data in the stream?
So far, the only way I know of to detect this condition at serialization time is to use full-trust reflection to compare the private method-pointer value in the original delegate with the value I get from reconstructing the delegate using its publicly visible properties.