Q:

How to serialize a delegate that points to the base of an overridden virtual method?

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.

A:

Interesting question. I've found one very hacky way of detecting it: create a copy using the public properties, and check for equality with the original. Sample code showing it working:
using System;
using System.Linq;
using System.IO;

class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Base");
    }
}

class Derived : Base
{
    public override void Foo()
    {
        Console.WriteLine("Derived");
    }

    public Action NonVirtualAction { get { return base.Foo; } }
    public Action VirtualAction { get { return Foo; } }
}

class Program
{
    static void Main()
    {
        var derived = new Derived();
        var virtualAction = derived.VirtualAction;
        var nonVirtualAction = derived.NonVirtualAction;

        var virtualCopy = CreateCopy(virtualAction);
        var nonVirtualCopy = CreateCopy(nonVirtualAction);

        Console.WriteLine(virtualCopy.Equals(virtualAction)); // True
        Console.WriteLine(nonVirtualCopy.Equals(nonVirtualAction)); // False
    }

    static Delegate CreateCopy(Delegate del)
    {
        // TODO: Validate it's not multi-cast
        return Delegate.CreateDelegate(del.GetType(), del.Target, del.Method);
    }
}

I don't know how you'd actually create it though... or whether there are other situations where this "equality of copy" would give false positives.

