代码之家  ›  专栏  ›  技术社区  ›  plinth

如何在F中实现ISerializable#

  •  2
  • plinth  · 技术社区  · 16 年前

    假设你从这个存根开始:

    [<Serializable>]
    type Bounderizer =
    val mutable _boundRect : Rectangle
    
    new (boundRect : Rectangle) = { _boundRect = boundRect ; }
    new () = { _boundRect = Rectangle(0, 0, 1, 1); }
    new (info:SerializationInfo, context:StreamingContext) =
        { // to do
        }
    
    interface ISerializable with
        member this.GetObjectData(info, context) =
            if info = null then raise(ArgumentNullException("info"))
            info.AddValue("BoundRect", this._boundRect)
    
        // TODO - add BoundRect property
    

    问题是规范中说,“一般来说,如果类没有被密封,这个构造函数应该受到保护。”F#没有一个protected关键字-那么我该怎么做呢?

    1. 必须实现ISerializable

    编辑-有趣的额外信息

    3 回复  |  直到 16 年前
        1
  •  2
  •   plinth    16 年前

    目前使用原样的语言是不可能做到这一点的。这是可能的,我有两种方法。

    第二个,我正在调查,是用

    [<Protected>]
    

    然后用 CCI

    Cecil 最终得到以下代码:

    首先是F中的一个属性#

    开放系统

    [<AttributeUsage(AttributeTargets.Method ||| AttributeTargets.Constructor, AllowMultiple=false, Inherited=true)>]
    type MyProtectedAttribute() =
        inherit System.Attribute()
    

    下面的应用程序是 :

    using System;
    using System.Collections.Generic;
    using System.Data.Linq;
    using System.Text;
    using Mono.Cecil;
    using Mono.Collections.Generic;
    using System.IO;
    
    namespace AddProtectedAttribute
    {
        class Program
        {
            static void Main(string[] args)
            {
                if (args.Length != 1 || args.Length != 3)
                {
                    Console.Error.WriteLine("Usage: AddProtectedAttribute assembly-file.dll /output output-file.dll");
                    return;
                }
    
                string outputFile = args.Length == 3 ? args[2] : null;
    
                ModuleDefinition module = null;
                try
                {
                    module = ModuleDefinition.ReadModule(args[0]);
                }
                catch (Exception err)
                {
                    Console.Error.WriteLine("Unable to read assembly " + args[0] + ": " + err.Message);
                    return;
                }
    
                foreach (TypeDefinition type in module.Types)
                {
                    foreach (MethodDefinition method in type.Methods)
                    {
                        int attrIndex = attributeIndex(method.CustomAttributes);
                        if (attrIndex < 0)
                            continue;
                        method.CustomAttributes.RemoveAt(attrIndex);
                        if (method.IsPublic)
                            method.IsPublic = false;
                        if (method.IsPrivate)
                            method.IsPrivate = false;
                        method.IsFamily = true;
                    }
                }
    
                if (outputFile != null)
                {
                    try
                    {
                        module.Write(outputFile);
                    }
                    catch (Exception err)
                    {
                        Console.Error.WriteLine("Unable to write to output file " + outputFile + ": " + err.Message);
                        return;
                    }
                }
                else
                {
                    outputFile = Path.GetTempFileName();
                    try
                    {
                        module.Write(outputFile);
                    }
                    catch (Exception err)
                    {
                        Console.Error.WriteLine("Unable to write to output file " + outputFile + ": " + err.Message);
                        if (File.Exists(outputFile))
                            File.Delete(outputFile);
                        return;
                    }
                    try
                    {
                        File.Copy(outputFile, args[0]);
                    }
                    catch (Exception err)
                    {
                        Console.Error.WriteLine("Unable to copy over original file " + outputFile + ": " + err.Message);
                        return;
                    }
                    finally
                    {
                        if (File.Exists(outputFile))
                            File.Delete(outputFile);
                    }
                }
            }
    
            static int attributeIndex(Collection<CustomAttribute> coll)
            {
                if (coll == null)
                    return -1;
                for (int i = 0; i < coll.Count; i++)
                {
                    CustomAttribute attr = coll[i];
                    if (attr.AttributeType.Name == "MyProtectedAttribute")
                        return i;
                }
                return -1;
            }
        }
    }
    

    最后,用MyProtectedAttribute修饰要保护的方法,并作为后期构建步骤运行C#app。

        2
  •  1
  •   Dmitry Lomov    16 年前

        3
  •  1
  •   desco    16 年前

    事实上,受保护的修饰语不是强制执行,而是 recommendation

    在反序列化过程中,SerializationInfo使用为此目的提供的构造函数传递给类。当对象被反序列化时,任何放置在构造函数上的可见性约束都被忽略;因此可以将类标记为public、protected、internal或private。

    所以这应该有效:

    [<Serializable>]
    type Bounderizer =
        val mutable _boundRect : Rectangle
    
        new (boundRect : Rectangle) = { _boundRect = boundRect ; }
        new () = { _boundRect = Rectangle(0, 0, 1, 1); }
        private new (info:SerializationInfo, context:StreamingContext) =
            Bounderizer(info.GetValue("BoundRect", typeof<Rectangle>) :?> Rectangle)
            then
                printfn "serialization ctor"
    
        interface ISerializable with
            member this.GetObjectData(info, context) =
                if info = null then raise(ArgumentNullException("info"))
                info.AddValue("BoundRect", this._boundRect)
    
        override this.ToString() = this._boundRect.ToString()
    
    let x = Bounderizer(Rectangle(10, 10, 50, 50))
    let ms = new MemoryStream()
    let f = new BinaryFormatter()
    f.Serialize(ms, x)
    ms.Position <- 0L
    let y = f.Deserialize(ms) :?> Bounderizer
    printfn "%O" y
    (*
    serialization ctor
    {X=10,Y=10,Width=50,Height=50}
    *)