[英]Creating new AppDomain in F# Interactive
I need the ability to create a new AppDomain in F# interactive in order to host multiple WPF applications. 我需要能够在F#interactive中创建一个新的AppDomain,以便托管多个WPF应用程序。 I don't have any problem getting the necessary functionality to work in a compiled F# application, but for some reason getting it to work in F# interactive doesn't seem to be possible.
我在编译的F#应用程序中获得必要的功能没有任何问题,但由于某种原因使其在F#interactive中工作似乎不可能。
Here is the simplest possible case:- 这是最简单的案例: -
#r "PresentationCore.dll"
#r "PresentationFramework.dll"
#r "System.Xaml.dll"
#r "WindowsBase.dll"
open System
open System.Threading
open System.Windows
type myClass() =
let domain = AppDomain.CreateDomain("another domain")
//this function starts a WPF app
let funct() =
let WPFStart() =
let app = Application()
let win = Window()
app.Run(win) |> ignore
let thread = Thread WPFStart
thread.IsBackground <- true
thread.SetApartmentState ApartmentState.STA
thread.Start()
do CrossAppDomainDelegate(funct) |> domain.DoCallBack
myClass();;
I always get back something along the lines of 我总是回过头来做些什么
System.Runtime.Serialization.SerializationException: Type is not resolved
for member 'FSI_0002+-ctor@24,FSI-ASSEMBLY, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null'.
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at FSI_0002.myClass..ctor()
at <StartupCode$FSI_0005>.$FSI_0005.main@()
Stopped due to error
What do I need to do to get this to work in F# interactive? 我需要做些什么才能在F#interactive中使用它?
Intro from the docs : 来自文档的介绍:
F# Interactive attempts to compile the code and, if successful, it executes the code and prints the signature of the types and values that it compiled.
F#Interactive尝试编译代码,如果成功,它将执行代码并打印其编译的类型和值的签名。
The main gotcha lies in the compilation step 主要问题在于编译步骤
typeof<myClass>.Assembly.FullName
Output: 输出:
val it : string = "FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
In order to compile the code fsi uses a dynamic assembly to host all types created during a session. 为了编译代码, fsi使用动态程序集来托管会话期间创建的所有类型。 The key element here is that other domains won't be able to resolve these types without a reference to that containing assembly.
这里的关键元素是,如果没有对包含程序集的引用,其他域将无法解析这些类型。 However, getting a hold of the assembly from other app domains proves to be non-trivial.
但是,从其他应用程序域中获取程序集证明是非平凡的。 Mainly because we're dealing with a dynamic assembly.
主要是因为我们正在处理动态装配。
let asm = typeof<myClass>.Assembly
asm.IsDynamic // val it : bool = true
Meaning, it only exists in memory of fsi 's default appdomain. 这意味着,它只存在于FSI的默认应用程序域的内存。 Both lookups below throw
下面的两个查找都抛出
System.NotSupportedException: The invoked member is not supported in a dynamic assembly.
System.NotSupportedException:动态程序集中不支持调用的成员。
asm.Location
asm.CodeBase
Typically, you'd want to persist to disk first, ref remarks - Restrictions on emitting to remote application domains : 通常,您希望首先保留到磁盘,引用注释 - 发送到远程应用程序域的限制 :
Some scenarios require a dynamic assembly to be created and executed in a remote application domain.
某些方案需要在远程应用程序域中创建和执行动态程序集。 Reflection emit does not allow a dynamic assembly to be emitted directly to a remote application domain.
Reflection emit不允许将动态程序集直接发送到远程应用程序域。 The solution is to emit the dynamic assembly in the current application domain, save the emitted dynamic assembly to disk, and then load the dynamic assembly into the remote application domain.
解决方案是在当前应用程序域中发出动态程序集,将发出的动态程序集保存到磁盘,然后将动态程序集加载到远程应用程序域中。
Successfully casting the dynamic assembly to AssemblyBuilder
would expose a Save
method. 成功将动态程序集强制转换为
AssemblyBuilder
将公开Save
方法。 Unfortunately, this workflow has been sealed off as well. 不幸的是,这个工作流程也被封锁了。
open System.Reflection.Emit
let builder = asm :?> AssemblyBuilder
Throws 抛出
System.InvalidCastException: Unable to cast object of type 'System.Reflection.Emit.InternalAssemblyBuilder' to type 'System.Reflection.Emit.AssemblyBuilder'
System.InvalidCastException:无法将类型为“System.Reflection.Emit.InternalAssemblyBuilder”的对象强制转换为“System.Reflection.Emit.AssemblyBuilder”
We're dealing with an internal type, clearly we're not ment to get our hands dirty. 我们正在处理一种内部类型,显然我们并没有把手弄脏。 From referencesource.microsoft.com :
来自referencesource.microsoft.com :
In the past, when InternalAssemblyBuilder was AssemblyBuilder, the untrusted user could down cast the Assembly to an AssemblyBuilder and emit code with the elevated permissions of the trusted code which origionally created the AssemblyBuilder via DefineDynamicAssembly.
在过去,当InternalAssemblyBuilder是AssemblyBuilder时,不受信任的用户可以将Assembly向下转换为AssemblyBuilder,并使用通过DefineDynamicAssembly创建AssemblyBuilder的受信任代码的提升权限发出代码。 Today, this can no longer happen because the Assembly returned via AssemblyGetAssemblies() will be an InternalAssemblyBuilder.
今天,这不再发生,因为通过AssemblyGetAssemblies()返回的程序集将是一个InternalAssemblyBuilder。
Alternatively, you could reflect over the types in the dynamic assembly and reconstruct them using a new AssemblyBuilder
and other helpers in the System.Reflection.Emit
namespace, but it all seems a tad on the tedious side. 或者,您可以反映动态程序集中的类型,并使用
System.Reflection.Emit
命名空间中的new AssemblyBuilder
和其他帮助程序重新构建它们 ,但这一切似乎都在乏味的一面。
To conclude, the way it's currently implemented you'll be swimming against the stream trying to expose fsi generated types to other domains. 总而言之,它目前实现的方式是你将游戏流试图将fsi生成的类型暴露给其他域。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.