F#Interactive:如何从System.Reflection.Assembly类导入类型

本文关键字:Assembly 导入 类型 Reflection System F#Interactive | 更新日期: 2023-09-27 18:19:36

对于脚本引擎,我尝试将C#集成到F#Interactive中,这样我就可以在F#Interactive中声明C#类。我已经成功地使用Microsoft CSharp代码提供程序将C#代码编译成了System.Reflection.Assembly对象(如果您感兴趣,请参阅下文)。因此,假设该脚本是System.Reflection.Assembly。使用

script.GetTypes()

我可以获得脚本中声明的所有类型的类型信息,例如,如果脚本在以下C#代码中声明:

    let CS_code="""
      namespace ScriptNS
          {
            public class Test
            {
                public string AString()
                {
                    return "Test";
                }
            }
          }"""

script.GetTypes将包含ScriptNS.Test类的类型信息。我想实现的是像F#Interactive中的任何其他类一样使用这个类,例如

let t=new ScriptNS.Test()

因此,我的问题是:我能以某种方式将Class导入FSI AppDomain吗?

谢谢你的帮助,

Andreas

附言:我发现的一种可能性是使用#r指令。一个可行的解决方案是:

open System.Reflection
open System.CodeDom.Compiler
// Create a code provider
let csProvider=new Microsoft.CSharp.CSharpCodeProvider()
// Setup compile options
let options=new CompilerParameters()
options.GenerateExecutable<-false
options.GenerateInMemory<-false
let tempfile="c:'Temp'foo.dll"
options.OutputAssembly<-tempfile
let result=csProvider.CompileAssemblyFromSource(options,CS_code)
let script=result.CompiledAssembly
#r "c:'Temp'foo.dll"
// use the type 
let t=new ScriptNS.Test()

然而,我对额外的dll不满意。

F#Interactive:如何从System.Reflection.Assembly类导入类型

这开始只是一个注释,但有点长:

这就是#r的作用:

        | IHash (ParsedHashDirective(("reference" | "r"),[path],m),_) -> 
            let resolutions,istate = fsiDynamicCompiler.EvalRequireReference istate m path 
            resolutions |> List.iter (fun ar -> 
                let format = 
                    if tcConfig.shadowCopyReferences then
                        let resolvedPath = ar.resolvedPath.ToUpperInvariant()
                        let fileTime = File.GetLastWriteTimeUtc(resolvedPath)
                        match referencedAssemblies.TryGetValue(resolvedPath) with
                        | false, _ -> 
                            referencedAssemblies.Add(resolvedPath, fileTime)
                            FSIstrings.SR.fsiDidAHashr(ar.resolvedPath)
                        | true, time when time <> fileTime ->
                            FSIstrings.SR.fsiDidAHashrWithStaleWarning(ar.resolvedPath)
                        | _ ->
                            FSIstrings.SR.fsiDidAHashr(ar.resolvedPath)
                    else
                        FSIstrings.SR.fsiDidAHashrWithLockWarning(ar.resolvedPath)
                fsiConsoleOutput.uprintnfnn "%s" format)
            istate,Completed

由此,我认为有趣的功能是:

member __.EvalRequireReference istate m path = 
    if Path.IsInvalidPath(path) then
        error(Error(FSIstrings.SR.fsiInvalidAssembly(path),m))
    // Check the file can be resolved before calling requireDLLReference 
    let resolutions = tcImports.ResolveAssemblyReference(AssemblyReference(m,path),ResolveAssemblyReferenceMode.ReportErrors)
    tcConfigB.AddReferencedAssemblyByPath(m,path)
    let tcState = istate.tcState 
    let tcEnv,(_dllinfos,ccuinfos) = 
        try
            RequireDLL tcImports tcState.TcEnvFromImpls m path 
        with e ->
            tcConfigB.RemoveReferencedAssemblyByPath(m,path)
            reraise()
    let optEnv = List.fold (AddExternalCcuToOpimizationEnv tcGlobals) istate.optEnv ccuinfos
    istate.ilxGenerator.AddExternalCcus (ccuinfos |> List.map (fun ccuinfo -> ccuinfo.FSharpViewOfMetadata)) 
    resolutions,
    { istate with tcState = tcState.NextStateAfterIncrementalFragment(tcEnv); optEnv = optEnv }

但看起来所有这些选项都使用了函数,这让它有点像死胡同。因此,我不太确定你想要的是否可能。