2016-02-01 9 views
33

Wir haben eine F # -Assembly (AssemblyOne), die eine andere F # -Assembly (AssemblyTwo) in einer einzigen Visual Studio 2012-Lösung referenziert. AssemblyTwo verweist auf eine C# -DLL (MyCSharpLib).F # Assembly-Referenzen, die Build-Probleme verursachen?

eine Funktion in AssemblyOne definiert ruft eine Funktion in AssemblyTwo definiert:

namespace AssemblyOne 

[<RequireQualifiedAccess>] 
module MyModuleA = 
    let FetchResult id = 
     let result = AssemblyTwo.MyModuleC.FetchResult id 
     result 

Die in AssemblyTwo aufgerufenen Funktion ruft eine andere Funktion (FetchActualResult()) in der gleichen Anordnung, die einen Parameter vom Typ nimmt MyCSharpType, die die referenzierten gehört C# DLL (MyCSharpLib):

namespace AssemblyTwo 

[<RequireQualifiedAccess>] 
module MyModuleB = 
    let FetchActualResult(myCSharpType:MyCSharpLib.MyCSharpType, id:int) 
     //return a result 

[<RequireQualifiedAccess>] 
module MyModuleC = 
    let FetchResult id = 
     let myCSharpType = new MyCSharpLib.MyCSharpType() 
     MyModuleB.FetchActualResult(myCSharpType, id) 

Die Lösung erstellt und baut in Visual Studio; jedoch, wenn wir versuchen, das Projekt von der Kommandozeile zu bauen MSBuild verwenden, die Build fehlschlägt, mit dem folgenden Fehler in den msbuild.log:

error FS0074: The type referenced through 'MyCSharpLib' is defined in an assembly that is not referenced. You must add a reference to assembly 'MyCSharpLib'. 

Es scheint, den Typen als Parameter ausgesetzt von MyCSharpLib im FetchActualResult() Funktionssignatur in AssemblyTwo verursacht den Fehler. AssemblyOne benötigt jetzt einen Verweis auf MyCSharpLib, obwohl AssemblyOne nicht direkt irgendetwas aus MyCSharpLib verwendet. Wenn wir den Parameter aus der Funktionssignatur entfernen, wird die Lösung fehlerfrei aufgebaut.

Wir dieses Problem weiter erforscht haben, indem Sie den Code mit den folgenden Anwendungsfälle zu replizieren ('->' bezeichnet das Bezugs assembly):

  • # F AssemblyOne -> F # AssemblyTwo ->MyCSharpLib (C# DLL) (tut bauen nicht)
  • F # AssemblyOne -> F # AssemblyTwo ->MyFSharpLib (F # DLL) (bauen sich nicht)
  • F # AssemblyOne -> F # AssemblyTwo -> C# AssemblyThree (Montage in derselben Lösung) (DOE n ot build)
  • F # AssemblyOne -> F # AssemblyTwo -> F # AssemblyThree (Montage in derselben Lösung) (baut)

kann dieses Verhalten zu erklären?

+0

Ich bin nicht sicher, was das verursacht, aber die üblichen Dinge, die Sie überprüfen können, sind (1) beziehen sich alle auf die gleiche Version von 'FSharp.Core.dll'? (2) Sind sie für den gleichen Zielrahmen zusammengestellt? –

+0

(1) sie alle verweisen auf die gleiche Version von 'FSharp.Core.dll' - Version 4.3.0.0 und (2) alle Assemblys target framework v4.5 – daithimurf

+1

Sind Sie sicher, dass Sie die gleiche MSBuild-Version verwenden, die VS verwendet ? Könnten Sie irgendwo ein vollständiges MSBuild-Protokoll veröffentlichen? – skolima

Antwort

1

Angenommen, es gibt einen Tippfehler in Ihren Quellen, wie DWright darauf hinwies, würde ich sagen, dass dieser Fehler nur dadurch entstehen kann, dass Sie mit diesem Code eine statische Klasse MyModuleB mit exponierten Methodenparameter eines externen Typs MyCharpType definieren .

Dies ist, wie der FSharp Code IL übersetzt (von ILSpy - neu übersetzt zu Csharp):

... 
public static class MyModuleB 
{ 
    public static string FetchActualResult(MyCSharpType myCSharpType, int id) 
    { 
     return myCSharpType.Fetch(id); 
    } 
} 

Wenn Sie also nicht die Art aussetzen, dass sie statisch sichtbar ist, könnte nicht der Fehler angezeigt. Dies würde jedoch von der Implementierung des Compilers abhängen.

Ich kann mir vorstellen, dass während der Kompilierung von MyModuleA, eine Konfiguration des Kompilierungsprozesses oder die Version des Compilers versuchen kann, MyModuleB zu "berühren" und somit versucht, den nicht referenzierten Parametertyp zu erreichen, und andere MyModuleB möglicherweise nicht berühren. Es kommt darauf an.

Das Problem scheint mir nicht im Kompilierungsprozess zu sein, sondern in der Tatsache, dass Sie die Verwendung eines Typs offen legen, für den Sie nicht auf seine Assembly verweisen.

0

Ich habe gerade einen ähnlichen Fall auf diese Weise gelöst. Versuche dies.

Am Ende MyModuleC, fügen Sie diese Zeile:

let fetchResult = FetchResult 

Und dann, in MyModuleA, rufen fetchResult statt FetchResult. Mit Argument natürlich.

Ja, ich weiß, es klingt albern, aber versuchen Sie es. Ich glaube, es wird die unerwünschte Abhängigkeit brechen.

Wenn Sie AssemblyTwo von C# wie es ist, verwenden Sie dieses Problem wahrscheinlich nicht. Es taucht auf, wenn Sie AssemblyTwo von F # konsumieren, also frage ich mich, ob es ein Problem mit dem F # -Compiler gibt, oder vielleicht hat es etwas mit Currying zu tun, das über mich hinausgeht. Wie auch immer, ich wünschte, der F # -Compiler wäre schlauer. Vielleicht sollte jemand ein Problem einreichen, es sei denn, es ist bereits geschehen.

Verwandte Themen