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

时间:2020-02-20 12:59:20

标签: c# .net f# decompiling

C#编译为IL,然后可以使用ILSpy或dotPeek轻松将其反编译为C#。

有没有工具可以将相同的IL反编译为F#?

即是否有偷偷摸摸的方法可以通过IL将C#转换为F#?

RATIONALE:

  • 我们有一个非常大的C#项目,希望“开始运行”。
  • 翻译是一项艰巨的工作。
  • 如果首遍翻译可以自动执行,我们可以在之后手工改进它。

即比用F#从头开始编写所有内容更快吗?

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

更多说明 是的,我们在C#中使用功能性的东西,但是由于各种原因,我们希望F#能够完全发挥功能。这个选择不在这里辩论,但感谢对此的评论。

3 个答案:

答案 0 :(得分:8)

惯用的F#代码使用不同的类型,方法和结构。从C#生成的IL到F#的“反编译”并没有什么好处,尤其是当您考虑可以很容易地与C#代码接口时。更糟糕的是,反编译任何内容都会使您失去很多信息-本地名称,常量,注释等各种杂乱无章的内容。这并非不可能,但是您要花费大量的精力来重建无论如何都是中间步骤的东西。

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

C#已经是一种“具有功能的”语言-不像F#那么整洁和富有表现力,但是您可以用F#进行的事情很少,但是用C#却不能以一种相当简单的方式完成。这意味着逐步转换为功能样式并不像听起来那样困难-如果您的目标是(出于某种原因;我希望您也有一个实际的目标,这是您无论如何都无法避免的工作)只是一个中间步骤:)功能代码。

答案 1 :(得分:3)

正如在这里回显的那样,当您编译为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#填充它。

和自动化中一样:

enter image description here

答案 2 :(得分:1)

我只是一个业余爱好者,所以我不保证以下内容是完全正确的...首先,我将假设您当前的C#库是用惯用的C#编写的,因此您当前的c#项目遵循的是面向对象的范例。如果这是正确的,并且您希望“完全正常运行”,那么您唯一的实际选择就是按照功能范例重新编写项目。如果存在这样的IL转换器,则转换后的对象将以面向对象的方式将C#编译为F#(F#是功能优先的语言,但也可以用作面向对象的语言)。此外,正如其他人指出的那样,您可以从F#调用C#代码,但这并不能将C#项目转换为以功能方式起作用。您仍然必须按照设计使用的方式使用C#项目-通过F#以面向对象的方式使用。您也许可以在F#中为C#程序编写某种形式的包装程序,以使其发挥功能,但是如果C#项目基于对象层次结构,那么这可能并不那么琐碎,您可能会发现自己并没有这样做。最后得到一个功能齐全的包装器。