【问题标题】:Type provider calling another dll in F#在 F# 中调用另一个 dll 的类型提供程序
【发布时间】:2012-04-27 20:17:00
【问题描述】:

在为提供的类型构建内部表示时,我在引用中间接调用了我的类型的内部表示,即另一个 dll,我可以修改其代码。

目前,当我使用类型提供程序时,告诉我找不到这样的 dll:

“无法加载文件或程序集 xxxx 或其依赖项之一”

不过,当我使用 Process Explorer 检查 VS 时,我可以看到 dll XXX 已加载... 有什么办法让引号中的代码接受来自外部 dll 的代码?

** 更新**

我尝试了一个简化的示例,似乎可以调用这样的外部 dll 而无需做任何特殊的事情。在我的情况下,所有依赖的 dll XXX 都已加载,当我调试 devenv.exe 本身时,我会在进程资源管理器以及模块窗口中看到它们......

我不知道去哪里找。这是内部异常。

** 更新**

如果我将 xxx dll 及其依赖项复制到此路径之一,则编译器可以正常工作。 我仍然想知道什么可以触发 devenv.exe 以正确显示它们已加载但无法访问。

=== Pre-bind state information ===
LOG: User = xxx\Administrator
LOG: DisplayName = bloombergapi, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\11.0\devenv.exe.config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PublicAssemblies/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PublicAssemblies/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PrivateAssemblies/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PrivateAssemblies/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Microsoft/TemplateProviders/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Microsoft/TemplateProviders/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Platform/Debugger/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Platform/Debugger/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PrivateAssemblies/DataCollectors/bloombergapi.DLL.

...

回答

似乎不可能调用将另一个库中的类型作为参数的函数。 联合类型有效,但不是正确的类型...... 如下图所示

--库.dll

namespace Library

module SampleModule = 
     type LocalUnion = | LocalUnion  of int

     type Localtype() = 
        member x.value = 2

--库TP.dll

namespace LibraryTP

module Module =
   open System.Reflection
   open Samples.FSharp.ProvidedTypes
   open FSharpx.TypeProviders.DSL
   open Microsoft.FSharp.Core.CompilerServices

   let f a = 
     Library.SampleModule.sampleFunction a a 

   let g (a:Library.SampleModule.LocalUnion) = 
      let (Library.SampleModule.LocalUnion(v)) = a
      v

   let ftype (a:Library.SampleModule.Localtype) = 
        a.value

   let createTP ns =
       erasedType<obj> (Assembly.GetExecutingAssembly()) ns "Outside"
       |> staticParameter "file"
          (fun typeName (parameterValues:string) ->
               erasedType<obj> (Assembly.GetExecutingAssembly()) ns typeName
               |+!> (   provideProperty 
                           "test"                             //OK
                           typeof<float>                   
                           (fun args -> <@@  g ( f 2 ) @@>)      
                         |> makePropertyStatic
                     )
               |+!> (   provideProperty 
                           "test2"                             //KO
                           typeof<int>                   
                           (fun args -> <@@ ftype ( Library.SampleModule.Localtype())  @@>)   
                        |> makePropertyStatic   
                     )
                  )

   [<TypeProvider>]
   type public CustomTypeProvider(cfg:TypeProviderConfig) as this =
      inherit TypeProviderForNamespaces()

      do this.AddNamespace("TP", [createTP "TP"])

   [<TypeProviderAssembly>]
   do()

--Program.fs

   type sampleValue = TP.Outside<""> 

   [<EntryPoint>] 
   let main(args) = 
      let t = sampleValue.Test        //OK
      let tt = sampleValue.Test2      //KO 

【问题讨论】:

  • 我猜是个愚蠢的问题,但你确定 dll XXX 的所有依赖项也都加载到内存中了吗?

标签: visual-studio dll f# type-providers


【解决方案1】:

您的程序集可能会加载到不同的binding context。当引用被反序列化时,它可能会尝试将程序集加载到一个绑定上下文,即使程序集已经加载到另一个上下文,这种尝试也可能会失败。作为类型提供程序设计时程序集中的解决方法,您可以将处理程序添加到 AssemblyResolve event 并尝试在已加载程序集的列表中查找目标程序集。

    do System.AppDomain.CurrentDomain.add_AssemblyResolve(fun _ args ->
        let name = System.Reflection.AssemblyName(args.Name)
        let existingAssembly = 
            System.AppDomain.CurrentDomain.GetAssemblies()
            |> Seq.tryFind(fun a -> System.Reflection.AssemblyName.ReferenceMatchesDefinition(name, a.GetName()))
        match existingAssembly with
        | Some a -> a
        | None -> null
        )

【讨论】:

  • 就是这样。非常感谢您非常的建议,一百万年我都不会想到这一点。你对那些新打字机还不错。
  • 当我尝试这个时,所需的程序集(显然)没有加载,所以我扩展了这个想法,让 ResolveEventHandler 也在父目录中查找“包”文件夹并在其中查找匹配的 DLL在那里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
相关资源
最近更新 更多