.NET 4.0为什么有一个新的GAC?

304

%windir%\Microsoft.NET\assembly\ 是新的全局程序集缓存(GAC)。这是否意味着现在我们需要管理两个GAC,一个用于.NET 2.0-3.5应用程序,另一个用于.NET 4.0应用程序?

4个回答

183

是的,由于存在两个不同的全局程序集缓存(GAC),因此您需要单独管理它们。

在.NET Framework 4.0中,GAC经历了一些变化。GAC被分成两个部分,每个CLR一个。

.NET Framework 2.0和.NET Framework 3.5使用的CLR版本都是CLR 2.0。在前两个框架版本中,没有必要拆分GAC。问题出现在Net Framework 4.0中,这会破坏旧应用程序。

为避免CLR 2.0和CLR 4.0之间的问题,GAC现在被拆分为每个运行时的私有GAC。主要变化是CLR v2.0应用程序现在无法看到GAC中的CLR v4.0程序集。

来源

为什么?

似乎是因为.NET 4.0中发生了CLR更改,而2.0到3.5没有。1.1到2.0 CLR也发生了同样的事情。GAC似乎具有存储不同版本程序集的能力,只要它们来自相同的CLR即可。他们不想破坏旧应用程序。

请参阅MSDN关于4.0中GAC更改的信息

例如,如果.NET 1.1和.NET 2.0共享同一个GAC,那么从这个共享的GAC加载程序集的.NET 1.1应用程序可能会获取.NET 2.0程序集,从而破坏.NET 1.1应用程序。.NET Framework 2.0和.NET Framework 3.5使用的CLR版本都是CLR 2.0。因此,在前两个框架版本中没有必要拆分GAC。在Net Framework 4.0中,旧版(在本例中为.NET 2.0)应用程序被破坏的问题再次出现,此时CLR 4.0发布。因此,为避免CLR 2.0和CLR 4.0之间的干扰问题,现在将GAC分成每个运行时的私有GAC。随着CLR在未来版本中的更新,您可以期望相同的事情发生。如果只更改语言,则可以使用相同的GAC。

18
那篇博客仅仅是在重申原帖的发现,它并没有解释为什么需要拆分GAC。这并不明显,因为原本的GAC完全可以将4.0程序集分开。他们有一个新的[AssemblyVersion]。 - Hans Passant
1
@Hans:也许不是确切的原因,但确实有说:“为了避免CLR 2.0和CLR 4.0之间的问题”,此外该问题包含两个问题。第二个问题是:“这是否意味着现在我们必须管理两个GAC,一个用于.NET 2.0-3.5应用程序,另一个用于.NET 4.0应用程序?” - Brian R. Bondy

68

我也想知道为什么有两个全局程序集缓存(GAC),在.NET 4.0 has 2 Global Assembly Cache (GAC)评论区中,Mark Miller给出了以下解释:

Mark Miller说... 2010年6月28日下午12:13

感谢您的文章。"干扰问题"是有意模糊的。在写作时,这些问题仍在调查中,但很明显存在几个破碎的场景。

例如,一些应用程序使用Assemby.LoadWithPartialName来加载一个程序集的最高版本。如果最高版本是使用v4编译的,那么v2(3.0或3.5)的应用程序将无法加载它,并且应用程序将崩溃,即使有一个版本可以正常工作。最初,我们将GAC分区到其原始位置下,但这会导致某些Windows升级方案出现问题。这两个问题都涉及已经发布的代码,因此我们将我们的(版本分区的GAC移动到另一个地方。

这对大多数应用程序不会产生任何影响,并且不会增加任何维护负担。这两个位置只能使用本机GAC API访问或修改,这些API按预期处理分区。这种情况出现的地方是通过公开GAC路径的API,例如GetCachePath,或检查加载到托管代码中的mscorlib的路径。

值得注意的是,当我们发布v2并引入体系结构作为程序集标识的一部分时,我们还修改了GAC位置。这些添加了GAC_MSIL、GAC_32和GAC_64,尽管仍然在%windir%\assembly下。不幸的是,这对于此版本来说不是一个选项。

希望能帮助未来的读者。

66

这样做似乎没有太多意义,原来的全局程序集缓存(GAC)已经能够存储不同版本的程序集。而且,几乎没有理由认为一个程序会意外引用错误的程序集,所有.NET 4程序集的[AssemblyVersion]都被提升到了4.0.0.0。新的进程内并行特性不应该改变这一点。

我的猜测是:已经有太多的.NET项目违反了“永远不要直接引用GAC中的任何内容”的规则。我在这个网站上看到过几次这样的情况。

唯一避免破坏这些项目的方法就是移动GAC。在微软看来,向后兼容性是神圣的。


1
@Hans Passant:您所说的“永远不要直接引用GAC中的任何内容”规则是什么意思? - Max Toro
2
@Max:你的机器上有两份.NET程序集的副本。其中一份是用来作为参考程序集的,位于c:\windows\microsoft.net和c:\program files\reference assemblies。另一份则是运行时所使用的,在c:\windows\assembly下,它们并不相同,64位就是其中一个例子。微软尽力避免任何人通过shell扩展处理程序或者 添加引用 对话框引用GAC中的程序集,但不是100%有效。 - Hans Passant
2
@Hans Passant:“而且很少有理由认为程序会意外引用错误的程序集”,我认为关键在于Assembly.LoadWithPartialName,如果GAC上有两个版本的程序集会发生什么? - Max Toro
@Hans Passant:就像你所说的,引用了错误的程序集不是问题,加载了错误的程序集才是问题。 "例如,如果.NET 1.1和.NET 2.0共享同一个GAC,那么从该共享GAC加载程序集的.NET 1.1应用程序可能会获取.NET 2.0程序集,从而破坏.NET 1.1应用程序。" http://msdn.microsoft.com/en-us/magazine/dd727509.aspx - Max Toro
@Max:这是完全相同的论点,但没有解释它如何发生。 "泄漏" 对我来说没有意义。 这开始闻起来像“宁愿安全也不要后悔”。 - Hans Passant
显示剩余4条评论

0
在.NET Framework 4.0中,GAC经历了一些变化。GAC被分成两个部分,每个CLR一个。
.NET Framework 2.0和.NET Framework 3.5都使用CLR 2.0版本。在之前的两个框架版本中,没有必要拆分GAC。这导致在Net Framework 4.0中破坏了旧应用程序的问题。
为避免CLR 2.0和CLR 4.0之间的问题,现在将GAC分成每个运行时的私有GAC。主要变化是CLR v2.0应用程序现在无法看到GAC中的CLR v4.0程序集。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接