【问题标题】:F# Interactive: How to import type from System.Reflection.Assembly classF# Interactive:如何从 System.Reflection.Assembly 类导入类型
【发布时间】:2014-08-26 09:47:38
【问题描述】:

对于脚本引擎,我尝试将 C# 集成到 F# Interactive 中,以便我可以在 F# Interactive 中声明 C# 类。我已经设法使用 Microsoft CSharp Code Provider 将 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()

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

感谢您的帮助,

安德烈亚斯

附:我发现的一种可能性是使用 #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 不满意。

【问题讨论】:

    标签: c# reflection f# f#-interactive


    【解决方案1】:

    这开始是一条评论,但有点长:

    这就是#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 }
    

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多