65.9K
CodeProject 正在变化。 阅读更多。
Home

匿名方法序列化

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (5投票s)

2009年2月12日

CPOL
viewsIcon

43987

匿名方法序列化

引言

在 C# 中,匿名方法无法被序列化(除非它们不引用任何堆栈变量)。最简单的解决方案是为该方法生成的匿名类添加 [Serializable] 属性,但由于(据我所知)目前还无法做到这一点,因此我们必须使用这种“技巧”。

这是 Jeremy Thomas 版本的一个更新版本,可以在这里找到,改进之处在于它也支持嵌套委托和任何委托。

请注意,此代码未经充分测试。 另外请注意,匿名方法内部引用的任何内容也会被序列化,包括 this。 这意味着,如果您序列化引用 this 的委托,然后再次反序列化并运行它,那么 this 将引用该对象的新的副本。

使用代码 

formater.Serialize(stream, new SerializeDelegate(myDelegate));

代码

[Serializable]
public class SerializeDelegate : ISerializable
{
    internal SerializeDelegate(Delegate delegate_)
    {
        this.delegate_ = delegate_;
    }

    internal SerializeDelegate(SerializationInfo info, StreamingContext context)
    {
        Type delType = (Type)info.GetValue("delegateType", typeof(Type));

        //If it's a "simple" delegate we just read it straight off
        if (info.GetBoolean("isSerializable"))
            this.delegate_ = (Delegate)info.GetValue("delegate", delType);

        //otherwise, we need to read its anonymous class
        else
        {
            MethodInfo method = (MethodInfo)info.GetValue("method", typeof(MethodInfo));

            AnonymousClassWrapper w = 
                (AnonymousClassWrapper)info.GetValue
			("class", typeof(AnonymousClassWrapper));

            delegate_ = Delegate.CreateDelegate(delType, w.obj, method);
        }
    }

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("delegateType", delegate_.GetType());

        //If it's an "simple" delegate we can serialize it directly
        if ((delegate_.Target == null ||
            delegate_.Method.DeclaringType
                .GetCustomAttributes(typeof(SerializableAttribute), false).Length > 0) &&
            delegate_ != null)
        {
            info.AddValue("isSerializable", true);
            info.AddValue("delegate", delegate_);
        }

        //otherwise, serialize anonymous class
        else
        {
            info.AddValue("isSerializable", false);
            info.AddValue("method", delegate_.Method);
            info.AddValue("class", 
                new AnonymousClassWrapper
		(delegate_.Method.DeclaringType, delegate_.Target));
        }
    }

    public Delegate Delegate { get { return delegate_; } }

    Delegate delegate_;

    [Serializable]
    class AnonymousClassWrapper : ISerializable
    {
        internal AnonymousClassWrapper(Type bclass, object bobject)
        {
            this.type = bclass;
            this.obj = bobject;
        }

        internal AnonymousClassWrapper(SerializationInfo info, StreamingContext context)
        {
            Type classType = (Type)info.GetValue("classType", typeof(Type));
            obj = Activator.CreateInstance(classType);

            foreach (FieldInfo field in classType.GetFields())
            {
                //If the field is a delegate
                if (typeof(Delegate).IsAssignableFrom(field.FieldType))
                    field.SetValue(obj,
                        ((SerializeDelegate)info.GetValue
				(field.Name, typeof(SerializeDelegate)))
                            .Delegate);
                //If the field is an anonymous class
                else if(!field.FieldType.IsSerializable)
                    field.SetValue(obj,
                        ((AnonymousClassWrapper)info.GetValue
				(field.Name, typeof(AnonymousClassWrapper)))
                            .obj);
                //otherwise
                else
                    field.SetValue(obj, info.GetValue(field.Name, field.FieldType));
            }
        }

        void ISerializable.GetObjectData
		(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("classType", type);

            foreach (FieldInfo field in type.GetFields())
            {
                //See corresponding comments above
                if (typeof(Delegate).IsAssignableFrom(field.FieldType))
                    info.AddValue(field.Name, new SerializeDelegate
					((Delegate)field.GetValue(obj)));
                else if (!field.FieldType.IsSerializable)
                    info.AddValue(field.Name, new AnonymousClassWrapper
				(field.FieldType, field.GetValue(obj)));
                else
                    info.AddValue(field.Name, field.GetValue(obj));
            }
        }

        public Type type; 
        public object obj;
    }
}

历史

  • 2009 年 2 月 12 日:初始发布
© . All rights reserved.