简体   繁体   中英

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

C# compiles into IL which is then easy to decompile back to C# using ILSpy or dotPeek.

Is there any tool that allows that same IL to be decompiled into F#?

ie is there a sneaky way to translate C# into F#, via IL?

RATIONALE:

  • We have a very large C# project and want to "go functional".
  • Translation is a massive job.
  • If a first-pass translation can be automated, we can improve it by hand after

ie would this be faster than writing everything from scratch in F#.

We are not yet experienced in F# hence the possible naivety of this question.

FURTHER NOTE Yes, we are using the functional stuff in C# but for various reasons we want to go fully functional with F#. That choice isn't up for debate here but thanks for the comments on this.

Idiomatic F# code uses different types, approaches and structure. There isn't much to gain from "decompiling" C#-generated IL to F#, especially when you consider that you can interface with C# code quite easily. To make things worse, decompiling anything makes you lose lots of information - names of locals, constants, comments all sort of mangling. It's not impossible, but you're wasting lots of effort rebuilding something that is an intermediate step anyway.

Break your C# code into parts that you can slowly replace with F# code. This way, you have a chance of producing good F# code, and incrementally replace everything as needed. Do not start writing anything from scratch - keep as much of the old code as possible, and only change what needs to be changed to improve the interfacing with the F# code.

C# is already quite a "functional-capable" language - not quite as neat and expressive as F#, but there's very few things you can do in F# but not in C# in a reasonably simple way. This means incrementally changing over to functional style isn't as difficult as it might sound - and it's work you can't avoid anyway, if your goal is (for some reason; I hope you have an actual goal as well, and this is just an intermediate step :) functional code.

As echoed here, you're losing precious information when you compile to IL. It's much more feasible to read the C# code to translate all of that high level info.

Just hacked together a 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();
        }

I tried it with a simple C# program:

        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());

Output:

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

Of course, the output is for a trivial program. It would take a lot more work to support a reasonable conversion, but maybe the conversion doesn't have to be perfect. Maybe if it gets you the scaffold, you could probably fill it in yourself in idiomatic F#.

And as always in automation:

在此处输入图片说明

I am just a hobbyist so I am not guaranteeing that the following is completely accurate... First off, I am going to assume that your current C# base is written in idiomatic C# so your current c# project follows the Object-Oriented paradigm. If this is accurate, and you are looking to go "fully functional" then your only real option is to re-write your project following the functional paradigm. If such an IL converter existed, then the converted would compile your C# into F# in an object-oriented manner (F# is a functional-first language but can also be used as an object-oriented language). Furthermore, as others have noted, you can call your C# code from F#, but that is not going to convert your C# project to act in a functional manner. You're still going to have to use your C# project in the manner it is designed to be used - in an object-oriented manner via F#. You might be able to write some form of wrapper around your C# program in F# to make it behave in a functional manner but if your C# project is based on an object hierarchy then this may not be too trivial and you may find that you don't end up with a fully functional wrapper.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM