如何在F#中实现了ISerializable实现了、如何在、ISerializable

2023-09-06 08:11:41 作者:黑糖沙琪玛

比方说,你这个存根开始:

Let's say you start off with this stub:

[<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#没有一个受保护的关键字 - ?让我怎么做到这一点

The issue is that the spec says, "In general, this constructor should be protected if the class is not sealed." F# doesn't have a protected keyword - so how do I do this?

约束(由于要求完美匹配现有的C#类在API级别):

Constraints (due to a requirement to match perfectly existing C# classes at the API level):

必须实现ISerializable的 构造必须得到保护

编辑 - 有趣的额外信息 F#的规范说,如果你覆盖所产生的功能将被保护的保护功能。这是不正确。如果没有指定访问,由此产生的倍率无论是公开的是什么(毁约)。

EDIT - interesting extra information The F# spec says that if you override a protected function that the resulting function will be protected. This is incorrect. If you don't specify accessibility, the resulting override will be public no matter what (breaking the contract).

推荐答案

这是不可能当前使用的语言为的就是能做到这一点。这是可能做到这一点,我有两种方法。

It is not possible to do this currently using the language as is. It is possible to do this and I have two ways.

首先是通过ILDASM运行输出程序集,正则表达式来你想要的方法声明,变市民,以你想要的方式家人,然后ILASM回来。 Ewwwww。

The first is to run the output assembly through ILDASM, regex to the method declaration you want, change 'public' to 'family' in the method you want, then ILASM it back. Ewwwww.

第二,我正在调查,是标记与

The second, which I'm investigating, is to tag the methods with

[<Protected>]

然后写出来与 CCI 的过滤器,以更改可访问所有的方法不是让ProtectedAttribute和然后删除该属性。这似乎不是运行一个正则表达式在文件少不体面的,但在工作中我的安全设置,认真恨CCI项目的源代码,所以我无法成功读取/ DECOM preSS /建造它。

then write a filter with CCI to change the accessibility on all methods than have the ProtectedAttribute and then remove the attribute. This seems less unseemly than running a regex over the file, but my security settings at work seriously hates the CCI project source, so I can't successfully fetch/decompress/built it.

编辑 - 这里是我的解决方案 - 我想CCI,但它没有准备好任务。最后我用塞西尔,并结束了与以下code:

EDIT - Here is my solution - I tried CCI, but it's not ready for the task. I ended up using Cecil and ended up with the following code:

首先,在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#应用程序作为生成后步骤。

finally, decorate the methods you want to be protected with MyProtectedAttribute and run the C# app as a post-build step.