visual studio proyecto outpath instalador generar genera ejecutable crear compilar como assemblyname c# visual-studio-2012 f# msbuild

c# - proyecto - generar.exe visual studio 2017



F#ensamblar referencias causando problemas de construcción? (2)

Tenemos un ensamblaje F # ( AssemblyOne ) que hace referencia a otro ensamblaje F # ( AssemblyTwo ) en una sola solución de Visual Studio 2012. AssemblyTwo tiene una referencia a una DLL C # ( MyCSharpLib ).

Una función definida en AssemblyOne llama a una función definida en AssemblyTwo :

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

La función llamada en AssemblyTwo llama a otra función ( FetchActualResult() ) en el mismo ensamblado que toma un parámetro de tipo MyCSharpType que pertenece a la DLL C # referenciada ( 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)

La solución compila y construye en Visual Studio; sin embargo, cuando tratamos de construir el proyecto desde la línea de comando usando MSBuild, la compilación falla, con el siguiente error en 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''.

Parece que el tipo expuesto como un parámetro de MyCSharpLib en la firma de la función FetchActualResult() en AssemblyTwo está causando el error. AssemblyOne ahora necesita una referencia a MyCSharpLib , aunque AssemblyOne no usa directamente nada de MyCSharpLib . Si eliminamos el parámetro de la firma de la función, la solución se genera sin errores.

Hemos explorado más este problema al replicar el código con los siguientes casos de uso (''->'' indica referencia de ensamblado):

  • F # AssemblyOne -> F # AssemblyTwo -> MyCSharpLib (C # DLL) (no se MyCSharpLib )
  • F # AssemblyOne -> F # AssemblyTwo -> MyFSharpLib (F # DLL) (no se MyFSharpLib )
  • F # AssemblyOne -> F # AssemblyTwo -> C # AssemblyThree (ensamble en la misma solución) (no se compila)
  • F # AssemblyOne -> F # AssemblyTwo -> F # AssemblyThree (ensamble en la misma solución) (compilaciones)

¿Se puede explicar este comportamiento?


Acabo de resolver un caso similar de esta manera. Prueba esto.

Al final de MyModuleC, agregue esta línea:

let fetchResult = FetchResult

Y luego, en MyModuleA, llame a fetchResult en lugar de FetchResult. Con argumento, por supuesto.

Sí, sé que suena tonto, pero intenta. Creo que romperá la dependencia no deseada.

Si usa AssemblyTwo from C # como está, probablemente no tenga este problema. Sale a la superficie cuando usted consume AssemblyTwo desde F #, entonces me pregunto si hay un problema con el compilador F #, o tal vez tiene algo que ver con el currying que me supera. De todos modos, me gustaría que el compilador F # fuera más inteligente. Tal vez alguien debería presentar un problema, a menos que ya esté hecho.


Asumiendo que hay un error tipográfico en sus fuentes como lo señaló DWright, diría que este error puede surgir solo por el hecho de que con este código define una clase estática MyModuleB con un parámetro de método expuesto de un tipo externo MyCharpType.

Así es como el código Fsharp se traduce a IL (de ILSpy - retraducido a Csharp):

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

Si no expone el tipo para que esté visible de forma estática, es posible que el error no aparezca. Esto, sin embargo, dependería de la implementación del compilador.

Me imagino que, durante la compilación de MyModuleA, una configuración del proceso de compilación o versión del compilador puede intentar "tocar" MyModuleB, y así tratar de llegar al tipo de parámetro sin referencia, y otro podría simplemente no tocar MyModuleB. Depende.

Así que el problema me parece que no está en el proceso de compilación, sino en el hecho de que expone el uso de un tipo para el que no hace referencia a su ensamblaje.