基因 fusion 类型_Fusion Loader上下文-无法将类型为“任意”的对象转换为类型为“任意”的对象...

基因 fusion 类型

基因 fusion 类型

It's funny how things you don't think about for a long time appear in twos or threes. This issue came up at work twice recently, and once via an email from a blog reader.

有趣的是,您长时间未考虑的事情出现在三三两两之间。 这个问题最近在工作中出现过两次,一次是通过博客阅读器的电子邮件发出的。

I blogged about part of this in 2004 when we were dealing with a lot of the icky complexities of the Loader (Fusion) in .NET. We used Mike Gunderloy's 2003 Binding Policy Article an a lot of testing to figure out how Fusion worked for us. We also are HUGE fans of Richard Grimes' amazing Fusion Workshop as a resource. Also, I just keep Fusion logging (FORCELOG) turned on all the time and logging to c:\fusionlogs.

当我们处理.NET中Loader(Fusion)的许多棘手复杂性时,我在2004年写了一篇博客。 我们使用了Mike Gunderloy在2003年的Binding Policy Article中进行了大量测试,以弄清楚Fusion是如何为我们工作的。 作为资源,我们还是Richard Grimes令人惊叹的Fusion Workshop的巨大粉丝。 另外,我一直保持融合日志记录(FORCELOG)始终打开并记录到c:\ fusionlogs。

Anyway, the issue was this error message about an InvalidCastException: 

无论如何,问题是关于InvalidCastException的以下错误消息:

System.InvalidCastException was unhandled
Message="Unable to cast object of type 'Plugin.Person' to type 'Plugin.Person'."
Source="LoaderContextSample"
StackTrace:
at LoaderContextSample.Program.Main(String[] args) in C:\LoaderContextSample\Program.cs:line 29
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

This can be initially very confusing because it says it's trying to cast type Person to type Person. Why aren't Person and Person the same, eh, Person?

最初,这可能会造成很大的混乱,因为它表示正在尝试将Person类型转换为Person类型。 为什么人和人不一样,人?

Suzanne Cook puts it best, emphasis mine:

苏珊娜·库克(Suzanne Cook)说得最好,请强调

For example, path matters when determining whether a type is castable to another type. Even if the assemblies containing the types are identical, if they're loaded from different paths, they're considered different assemblies and therefore their types are different. This is one reason why using contexts other than the Load context is risky. You can get into situations where the same assembly is loaded multiple times in the same appdomain (once in the Load context, once in the LoadFrom context, and even several times in neither context), and their corresponding types won't be castable.

例如,在确定一种类型是否可转换为另一种类型时,路径很重要。 即使包含类型的程序集是相同的,但是如果它们是从不同的路径加载的,它们也被视为不同的程序集,因此它们的类型也不同。 这就是为什么使用除Load上下文之外的其他上下文存在风险的原因之一 您可能会遇到在同一appdomain中多次加载同一程序集的情况(一次在Load上下文中,一次在LoadFrom上下文中,甚至多次在两个上下文中都不加载),并且它们的对应类型将不可转换。

If you have an assembly you reference, but you also have a plugin that you've loaded, perhaps via LoadFrom (bad), if you intend for the types to be the same but they are loaded from different paths, they are effectively different types.

如果你有一个装配您参考,但你也有已加载,可能通过LoadFrom(坏)插件,如果你打算为类型是相同的,但他们是从不同的路径加载,它们是有效的不同类型。

In this sample, I create a Person object via an assembly I've referenced the usual way, via Add Reference. Works great.

在此示例中,我通过添加引用通过通常引用的程序集创建了一个Person对象。 效果很好。

Then I load Person using Assembly.Load and create a Person via Reflection, then cast the object instance to the first kind of Person. Because I used Assembly.Load - usually the most appropriate Binding Context - the Loader (Fusion) finds the same assembly, and the Person Type created via Reflection is the same kind of Person as before. Works great. Note that Assembly.Load takes an Assembly Qualified Name like "Person" - not "Person.dll." Remember that Assembly QNs NEVER have .dll in their names.

然后,我使用Assembly.Load加载Person并通过Reflection创建一个Person,然后将对象实例转换为第一种Person。 因为我使用了Assembly.Load(通常是最合适的绑定上下文) ,所以Loader(融合)会找到相同的程序集,并且通过Reflection创建的Person Type与以前的Person类型相同。 效果很好。 请注意,Assembly.Load采用的程序集合格名称为“ Person”,而不是“ Person.dll”。 请记住,程序集QN的名称中永远不会包含.dll。

Then I load the Person from a different path. In this example I've copied Person.dll to Person2.dll via a Post-Build-Event to illustrate this, but the most common way this would happen is that you've got a static reference to an assembly in the GAC, but your Plugin design uses LoadFrom to load a DLL from another path. Then you try to cast them. LoadFrom will almost always lead you astray.

然后,我从另一个路径加载人 在此示例中,我已通过Post-Build-Event将Person.dll复制到Person2.dll进行了说明,但是最常见的方式是对GAC中的程序集进行静态引用,但是您的插件设计使用LoadFrom从另一个路径加载DLL。 然后,您尝试投射它们。 LoadFrom几乎总是会使您误入歧途。

If I was really serious I should have used the complete Assembly QN: Person, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, and I would have strong named it for Assembly verification purposes, but that's another post.

如果我真的很认真,我应该使用完整的Assembly QN: Person,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null ,并且我会强烈地将其命名为Assembly验证目的,但这是另一篇文章。

Here's part of the sample:

这是示例的一部分:

Person p = new Person("Franklin", "Ajaye");

//Use the Load Context...almost ALWAYS the right thing to do...
Assembly a = Assembly.Load("Person"); 
Type t = a.GetType("Plugin.Person");
object instance = t.InvokeMember(String.Empty,BindingFlags.CreateInstance, null, null, null);
Person p1 = (Person)instance;

//Use the LoadFrom...almost ALWAYS the *WRONG* thing to do...
Assembly a2 = Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Person2.dll"));
Type t2 = a2.GetType("Plugin.Person");
object instance2 = t2.InvokeMember(String.Empty,BindingFlags.CreateInstance, null, null, null);
Person p2 = (Person)instance2; //BOOM!


Lucky Line 13 is where the InvalidCastException happens and I see the dialog pictured at the top of this post. Boom.

幸运的第13行是发生InvalidCastException的地方,我看到该对话框顶部显示的对话框。 繁荣。

The Loader has a  lot of nuance, and it's helpful if you're building a large system with plugins and many points of extensibility to ask yourself - Where are my plugins on disks? What Types are shared? How are my plugins getting into memory?

加载程序有很多细微差别,如果您要构建一个带有插件并具有许多可扩展性的大型系统,请问自己-磁盘上的插件在哪里? 共享什么类型? 我的插件如何进入内存?

Here's what we documented a long time ago. This only applies to dynamically loaded assemblies:

这是我们很久以前记录的内容。 这仅适用于动态加载的程序集:

  • Assemblies will only EVER be loaded from the GAC based on a full bind (name, version, and public key token).  A partial bind with name and public key token only WON’T load from the GAC. 

    仅根据完全绑定(名称,版本和公共密钥令牌)从GAC加载程序集。 仅从GAC不会加载带有名称和公共密钥令牌的部分绑定。

    • If you reference an assembly with VS.NET you're asking for a full bind. If you say Assembly.Load("foo") you're asking for a partial bind.

      如果使用VS.NET引用程序集,则要求完全绑定。 如果您说Assembly.Load(“ foo”),则要求部分绑定。
  • However, the way this usually works is…

    但是,这通常的工作方式是…

    • You do a partial bind on assembly name, or name and public key token with Assembly.Load

      您对程序集名称或使用Assembly.Load的名称和公钥令牌进行部分绑定
    • Fusion (the code name for the Assembly Loader/Binder) starts walking the probing path looking for an assembly that matches the partial bind.

      Fusion(程序集加载程序/装订程序的代号)开始沿着探测路径移动,以查找与部分绑定匹配的程序集。
    • Counter Intuitive: If it finds one while probing (the first one) it will then attempt to use the strong name of the one it found to do a full bind against the GAC.

      违反直觉:如果它在探测时发现一个(第一个) ,则将尝试使用发现的那个名字的强名称来对GAC进行完全绑定

    • If it’s in the GAC, that’s the one that gets loaded.

      如果它在GAC中,那就是被加载的那个。
    • Any of that loaded assemblies will try to load from the GAC first without going to the probing path, since the embedded references constitute a full bind.

      由于嵌入的引用构成了完整的绑定,因此任何已加载的程序集都将尝试先从GAC加载而无需进入探测路径。
    • If they aren’t found in the GAC, then it will start probing.

      如果在GAC中找不到它们,它将开始进行探测。
    • It’ll grab the first one it finds in the probing path.  If the versions don’t match, Fusion fails.  If they do match, Fusion loads that one.

      它会抓住它在探测路径中找到的第一个。 如果版本不匹配,则Fusion将失败。 如果匹配,则Fusion会加载该文件。
    • So, if you specify a partial name, and the file is in the GAC, but not the probing path, the load fails, since there’s no way to do a full bind.  

      因此,如果您指定了部分名称,并且文件在GAC中,但不在探测路径中,则加载失败,因为无法进行完全绑定。

Here's the complete sample code from above if you like.

如果您愿意,这是上面的完整示例代码。

翻译自: https://www.hanselman.com/blog/fusion-loader-contexts-unable-to-cast-object-of-type-whatever-to-type-whatever

基因 fusion 类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值