Ich habe schon oft gelesen, dass
Aus F# oder einer anderen .NET-Sprache generierte Assemblies sind (fast) ununterscheidbar.
Damals experimentierte ich mit der Interoperabilität von F# und C# unter .NET 4 (Beta 2). Ich habe eine neue Lösung und ein C#-Projekt mit der folgenden Klasse erstellt:
public class MyClass {
public static int Add(int a, int b) { return a + b; }
}
Dann, auf einem F#-Projekt, nach dem Verweis auf das C#-Projekt, versuchte ich:
MyClsas.Add(4, 5) |> printfn "%d" // prints 9 (no kidding!)
So weit, so gut. Dann kam mir ein anderer Satz in den Sinn, den ich schon viele Male gelesen habe (vielleicht in verschiedenen Büchern):
Bei der Übergabe von Argumenten an Funktionen aus anderen .NET-Bibliotheken verwenden Sie eine Syntax wie ".MethodName(parm1, parm2)", d.h. die Parameter werden als Tupel übergeben.
Dazu kommt noch etwas, das ich einmal hier auf SO gelesen habe (aber ich konnte es nicht finden, um es zu verlinken), und zwar zu einer Frage, bei der der Auftraggeber versuchte, ein using wie [ 4, 5, 6 ]
(wenn er meinte [4; 5; 6]
) :
"Das Komma ist der 'Tupel-Erzeugungsoperator', für alles andere verwenden Sie das Semikolon."
Dann habe ich meine Klasse wie folgt geändert:
public class MyClass {
public static int Add(int a, int b) { return a + b; }
public static int Add(Tuple<int, int> a) { return a.Item1; }
}
Jetzt habe ich versucht, es auf F# zu verwenden:
MyClass.Add(4, 5) |> printf "%d" // prints ... (keep reading!)
Wenn man also die drei oben genannten Zitate zusammenzählt, kann man zu dem Schluss kommen, dass:
- F# erstellt ein Tupel, wenn es sieht
(4, 5)
- Dann wird die Überlast aufgerufen
Add(Tuple<int, int>)
- Es werden also 4
Zu meiner Überraschung, er druckte 9 . Ist das nicht interessant?
Was ist hier wirklich los? Die obigen Zitate und diese praktischen Beobachtungen scheinen im Widerspruch zu stehen. Können Sie die "Argumentation" von F# begründen und vielleicht auf einige MSDN-Dokumente verweisen, wenn möglich?
Danke!
EDITAR
(um weitere Informationen hinzuzufügen (aus der Antwort von Blindy))
Wenn Sie das tun:
MyClass.Add((4, 5)) |> printfn "%d" // prints 9
F# ruft die Add(Tuple<int, int>)
Überlastung.
Wenn Sie jedoch ein anderes F#-Projekt (also eine andere Assembly) mit diesem erstellen:
namespace MyFSharpNamespace
type MyFShapClass = class
static member Add x y = x + y
end
Sie können es in C# wie folgt verwenden
public static void Main(string[] args) {
MyFSharpNamespace.MyFSharpClass.Add(4, 5);
}
So weit, so gut. Nun, wenn Sie versuchen, es von F# (von einem anderen Projekt, eine andere Assembly) zu verwenden, müssen Sie tun:
MyFSharpNamespace.MyFSharpClass.Add 4 5 |> printfn "%d"
Wenn Sie die Argumente als (4, 5)
F# wird nicht kompiliert, weil Add
es int -> int -> int
und nicht (int * int) -> int
.
Was ist hier los?!?