.net - 如何在 F# 中实现 ISerialized

标签 .net f# constructor iserializable

假设您从这个 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# 没有 protected 关键字 - 那么我该如何做到这一点?

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

  1. 必须实现 ISerialized
  2. 必须保护构造函数

编辑 - 有趣的额外信息 F# 规范表示,如果您覆盖 protected 函数,则生成的函数将受到保护。这是不正确的。如果您不指定可访问性,则无论如何,生成的覆盖都将是公开的(违反契约(Contract))。

最佳答案

目前无法按原样使用该语言来执行此操作。这是可以做到的,我有两种方法。

第一种方法是通过 ILDASM 运行输出程序集,将正则表达式替换为所需的方法声明,将所需方法中的“public”更改为“family”,然后将 ILASM 返回。呃wwwwww。

我正在研究的第二个方法是用标记方法

[<Protected>]

然后用CCI编写一个过滤器更改除 ProtectedAttribute 之外的所有方法的可访问性,然后删除该属性。这看起来比在文件上运行正则表达式更不体面,但我工作中的安全设置非常讨厌 CCI 项目源,所以我无法成功获取/解压缩/构建它。

编辑 - 这是我的解决方案 - 我尝试了 CCI,但它还没有准备好执行任务。我最终使用了Cecil最终得到以下代码:

首先是 F# 中的属性

开放系统

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

然后以下应用程序是 Cecil 的客户端:

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# 应用程序。

关于.net - 如何在 F# 中实现 ISerialized,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3319274/

相关文章:

c# - 将解决方案发布到文件夹时出错 - 自托管 .NET

c# - 如何在 ASP.NET Core 中默认防止 CSRF

.net - 如何在 F# 中枚举枚举/类型

f# - F# Akka.NET 中的 System.create 错误

c++ - 复制构造函数省略?

c++ - 通过具有多个参数的构造函数隐式转换

.net - 在 .Net 项目中配置和使用 Broker API

.net - 有没有一种简单的方法来解码 PEVerify 错误和警告?

syntax - 此表达式的类型为 int 但此处与类型 unit 一起使用

c++ - 是否为成员变量自动调用默认构造函数?