对于脚本引擎,我尝试将C#集成到F#Interactive中,以便我可以在F#Interactive中声明C#类。我已经设法使用Microsoft CSharp Code Provider将C#-code编译成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吗?
感谢您的帮助,
安德烈亚斯
P.S。我发现的一种可能性是使用#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不满意。
答案 0 :(得分: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 }
但看起来所有这些选项都使用了函数,这使得它有点死路一条。因此,我不太确定你想要的是什么。