是否可以将 C# 编译成 IL,并将生成的 IL 反编译成 F#?

Is it possible to compile C# into IL and decompile the resulting IL into F#?

C# 编译成 IL,然后可以使用 ILSpy 或 dotPeek 轻松反编译回 C#。

是否有任何工具可以将相同的 IL 反编译为 F#?

即是否有通过 IL 将 C# 翻译成 F# 的偷偷摸摸的方法?

理由:

即这会比在 F# 中从头开始编写所有内容更快吗?

我们还没有 F# 经验,因此这个问题可能很天真。

进一步说明 是的,我们正在使用 C# 中的功能性内容,但出于各种原因,我们希望使用 F# 实现完整的功能性。这个选择不在这里讨论,但感谢您对此的评论。

地道的 F# 代码使用不同的类型、方法和结构。从 "decompiling" C# 生成的 IL 到 F# 没有太多好处,尤其是当您认为可以非常轻松地与 C# 代码交互时。更糟糕的是,反编译任何东西都会让你丢失很多信息——局部变量的名称、常量、注释等等。这并非不可能,但您正在浪费大量精力来重建无论如何都是中间步骤的东西。

将您的 C# 代码分解为可以慢慢替换为 F# 代码的部分。这样,您就有机会生成良好的 F# 代码,并根据需要逐步替换所有内容。不要从头开始编写任何东西 - 尽可能多地保留旧代码,并且只更改需要更改的内容以改进与 F# 代码的接口。

C# 已经是一种相当 "functional-capable" 的语言 - 不像 F# 那样整洁和富有表现力,但是您可以在 F# 中以相当简单的方式完成的事情很少,而在 C# 中则不能。这意味着逐渐转变为函数式风格并不像听起来那么困难——而且如果你的目标是(出于某种原因;我希望你也有一个实际目标,这就是你无法避免的工作)只是一个中间步骤 :) 功能代码。

正如此处所反映的那样,当您编译为 IL 时,您正在丢失宝贵的信息。阅读 C# 代码来翻译所有高级信息要可行得多。

刚刚拼凑了一个 SyntaxWalker

  public class FsVisitor : CSharpSyntaxWalker
        {
            public override void VisitUsingDirective(UsingDirectiveSyntax node)
            {
                PrintLn("open {0}", node.Name);
            }

            public override void VisitClassDeclaration(ClassDeclarationSyntax node)
            {
                PrintLn("type {0} =", node.Identifier);
                Enter();
                base.VisitClassDeclaration(node);
                Exit();
            }

            public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
            {
                var isStatic = node.Modifiers.Any(t => t.ValueText == "static");
                var modifiers = String.Join(" ", node.Modifiers);

                PrintLn("{0}{1} ({2}) = ",
                    isStatic ? $"{modifiers} member " : $"member {modifiers} this.",
                    node.Identifier,
                    String.Join(", ", node.ParameterList.Parameters.Select(p => $"{p.Identifier} : {p.Type}")));
                Enter();
                base.VisitMethodDeclaration(node);
                Exit();
            }

            public override void VisitInvocationExpression(InvocationExpressionSyntax node)
            {
                PrintLn("{0}", node);
                base.VisitInvocationExpression(node);
            }

            private StringBuilder builder = new StringBuilder();
            private int intendLevel = 0;

            void Enter() => intendLevel++;
            void Exit() => intendLevel--;

            void Print(string format, params object[] args)
            {
                if (format == null) return;
                builder.Append('\t', intendLevel);
                builder.AppendFormat(format, args);
            }

            void PrintLn(string format = default, params object[] args)
            {
                Print(format, args);
                builder.AppendLine();
            }

            public override string ToString() => builder.ToString();
        }

我用一个简单的 C# 程序试了一下:

        var code =
        @"    
        using System;

        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(""Hello World"");
                Console.ReadKey();
            }

            private void SayHello()
            {
                Console.WriteLine(""Hello"");
            }
        }";

    var visitor = new FsVisitor();
    visitor.Visit(CSharpSyntaxTree.ParseText(code).GetCompilationUnitRoot());
    Console.WriteLine(visitor.ToString());

输出:

open System
type Program =
        static member Main (args : string[]) =
                Console.WriteLine("Hello World")
                Console.ReadKey()
        member private this.SayHello () =
                Console.WriteLine("Hello")

当然,输出是针对一个普通程序的。 支持合理的转换需要做更多的工作,但也许转换不一定是完美的。也许如果它为您提供了脚手架,您可能可以使用惯用的 F# 自行填充它。

和自动化一样:

我只是一个业余爱好者,所以我不保证以下内容完全准确...首先,我假设您当前的 C# 基础是用惯用的 C# 编写的,因此您当前的 C# 项目遵循 Object - 面向范式。如果这是准确的,并且您希望 "fully functional" 那么您唯一真正的选择是按照功能范式重新编写您的项目。如果存在这样的 IL 转换器,那么转换后的程序会以面向对象的方式将 C# 编译成 F#(F# 是一种功能优先的语言,但也可以用作面向对象的语言)。此外,正如其他人所指出的,您可以从 F# 调用您的 C# 代码,但这不会将您的 C# 项目转换为以功能方式运行。您仍然必须按照设计使用的方式使用您的 C# 项目 - 通过 F# 以面向对象的方式。您可能能够在 F# 中围绕您的 C# 程序编写某种形式的包装器,使其以功能方式运行,但如果您的 C# 项目基于对象层次结构,那么这可能不是太微不足道,您可能会发现您不最终不会得到一个功能齐全的包装器。