[英]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# 代碼使用不同的類型、方法和結構。 將 C# 生成的 IL“反編譯”到 F# 並沒有什么好處,尤其是當您考慮到可以很容易地與 C# 代碼交互時。 更糟糕的是,反編譯任何東西都會讓你丟失大量信息——本地名稱、常量、注釋等等。 這並非不可能,但是您正在浪費大量精力來重建一些中間步驟。
將 C# 代碼分解成可以慢慢替換為 F# 代碼的部分。 這樣,您就有機會生成良好的 F# 代碼,並根據需要逐步替換所有內容。 不要從頭開始編寫任何東西 - 盡可能多地保留舊代碼,並且只更改需要更改的內容以改進與 F# 代碼的接口。
C# 已經是一種“功能強大”的語言 - 不像 F# 那樣簡潔和富有表現力,但是您可以在 F# 中以相當簡單的方式在 C# 中完成的事情很少,而在 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# 項目遵循面向對象的范例。 如果這是准確的,並且您希望“功能齊全”,那么您唯一真正的選擇是按照功能范式重新編寫您的項目。 如果存在這樣的 IL 轉換器,則轉換后的程序將以面向對象的方式將您的 C# 編譯為 F#(F# 是一種功能優先的語言,但也可以用作面向對象的語言)。 此外,正如其他人所指出的,您可以從 F# 調用您的 C# 代碼,但這不會將您的 C# 項目轉換為以功能方式運行。 您仍然必須按照設計使用的方式使用 C# 項目 - 通過 F# 以面向對象的方式使用。 您可能可以在 F# 中圍繞 C# 程序編寫某種形式的包裝器,使其以功能方式運行,但如果您的 C# 項目基於對象層次結構,那么這可能不是太簡單,您可能會發現您沒有最終得到一個功能齊全的包裝器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.