当InternalsVisibleToAttribute特性遭遇"强签名"
一、如何让Intenal成员暴露给另一个程序集我们知道Modifier为Internal的类型成员仅限于当前程序集能够访问,但是在某些情况下,我们希望将它们暴露给另一个程序集。比较典型的应用场景包括如下两种:
举个例子,如右图所示,我将某个组件定义在Lib项目中,而Test是与之对应的单元测试项目。定义在Lib中组建成员的可见性依赖于具体的设计,但是在很多情况下,单元测试用例为了尽可能覆盖较多的分支,需要调用一些Internal成员。比如,设置一些Internal属性,或者调用一些Internal方法。 我在Lib中定义了如下一个表示二维向量的Vector类,其中X和Y属性的Set方法为Internal。 1: public class Vector 3: private static void EnsureNotNull(object value,string parameterName) 5: if (null == value) 7: throw new ArgumentNullException(parameterName); 9: } 11: double Y { get; internal set; } 13: public Vector(double x,1)">double y) 15: this.X = x;
17: } 19: override bool Equals(object obj) 21: Vector vector = obj as Vector;
23: { 25: } 27: this.X == vector.X && this.Y == vector.Y; 29:? 31: { 33: EnsureNotNull(v2,1)">"v2"); 35: } 37: int GetHashCode()
39: this.X.GetHashCode() ^ this.Y.GetHashCode(); 41: } 在单元测试项目Test中,定义如下一个VectorFixture类型,用于测试向量相加的逻辑。为了测试方便,我在这里希望直接设置Vector的X和Y属性,而这两个属性的Set方式是Internal的。 2: class VectorFixture
4: [TestMethod] 6: { 8: var v2 = new Vector(3,4);
10:? 12: v1.Y = -2; 14: v2.Y = -4; 16: } 1: [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Test)] 二、如果对Lib添加强签名呢?在很多情况下,我们需要将最终的程序集以强命名的形式发布。为此,我们修改Lib项目设置,开启"Sign the assembly”开关,并创建一个密钥文件。 当完成上面的步骤后,Lib项目将不能通过编译,编译错误如下图所示。具体的错误信息为:“Friend assembly reference 'Test' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations.” 三、如果在InternalsVisibleToAttribute指定程序集的强名称(Strong Name)呢?从上面的出错消息中我们不难看出,编译错误的原因是:当自身具有强签名的情况下,通过InternalsVisibleToAttribute指定的程序集也需要具有强签名。那么,如果我们将单元测试项目Test也加上强签名,并将InternalsVisibleToAttribute特性指定成程序集的强名称,是否可以解决这个问题呢? 在对Test项目按照上面的步骤进行强签名后,并重新修改了应用在Lib程序集上的InternalsVisibleToAttribute特性设置,即设置成包含4个部分(名称、版本、语言文化和公钥令牌)的程序集强名称。 出错信息表明:通过InternalsVisibleToAttribute特性指定的程序集名称的时候,只能指定程序集名称(文件名),不能指定版本、语言文化和公钥令牌。
? 四、需要指定的是完整的公钥实际上对于上面的情况,需要指定的不是程序名的强命名,而是指定对程序集进行签名时采用的公钥。那么如何得到这个公钥呢?我们可以通过强名称(SN.exe)命令行工具直接将公钥从密钥文件中提取出来。 具体来说我们需要两个步骤:通过SN.exe结合-p开关从将包含公钥/私钥的密钥文件中提取公钥,并导入到指定的密钥文件中;然后执行SN.exe并结合使用-tp开关,将公钥文件中的公钥显示出来。 两个步骤地命令行输入和输出入下所示。其中Test.snk表示对单元测试项目进行签名的密钥文件,而Test.PK.snk则表示导出的只包含公钥的密钥文件。最终控制台显示出我们需要的完整的公钥:“0024000004800000940000000602000000240000525341310004000001000100c9d70c8b6c1eb494b113701099f43ef62efe8c9cf4310bda2061eff1cc91ffda4368848d3283d4d83e63087038e32ea25e0098891608ae48993bf16ea93362d10207de3a4dca263c145a6febf1784401948c2474c3f55713e6b97e9c1c3eef5b8966b879407b955b23404c62cd75fcf3598b6950d104a4ea97209ad051763ca4” 1: C:UsersjinnanDocumentsVisual Studio 2010ProjectsInternalsVisibilityTest>SN -p Test.snk Test.PK.snk
2: Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.1 Copyright (c) Microsoft Corporation. All rights reserved. 3: Public key written to Test.PK.snk 4: C:UsersjinnanDocumentsVisual Studio 2010ProjectsInternalsVisibilityTest>SN -tp Test.PK.snk
5: Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.1 Copyright (c) Microsoft Corporation. All rights reserved. 6: Public key is: 0024000004800000940000000602000000240000525341310004000001000100c9d70c8b6c1eb494b113701099f43ef62efe8c9cf4310bda2061eff1cc 7: 91ffda4368848d3283d4d83e63087038e32ea25e0098891608ae48993bf16ea93362d10207de3a4dca263c145a6febf1784401948c2474c3 8: f55713e6b97e9c1c3eef5b8966b879407b955b23404c62cd75fcf3598b6950d104a4ea97209ad051763ca4 9: Public key token is 8dba6a4f4e33b7dc 我们只需要将该公钥指定到InternalsVisibleToAttribute特性中即可: 2: 001000100c9d70c8b6c1eb494b113701099f43ef62efe8c9cf4310bda2061eff1cc91ffda4368848d3283d4d83e63087038e32ea25e0098891608ae48993bf16ea933
相关内容
推荐文章
站长推荐
热点阅读
|