对于脚本引擎,我尝试将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:Tempfoo.dll"
options.OutputAssembly<-tempfile
let result=csProvider.CompileAssemblyFromSource(options,CS_code)
let script=result.CompiledAssembly
#r "c:Tempfoo.dll"
// use the type
let t=new ScriptNS.Test()
然而,我对额外的dll不满意。
这开始只是一个注释,但有点长:
这就是#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 }
但看起来所有这些选项都使用了函数,这让它有点像死胡同。因此,我不太确定你想要的是否可能。