如何编译同时引用两个不同版本的Assembly的C#程序

症状:

请看下面三个代码以及对应的编译步骤,能看出什么问题出来吗?

ITest.cs:

1. using System;

2.

3. public interface ITest

4. {

5.     void TestMethod();

6. }

 

TestClass.cs:

1. using System;

2.

3. public class TestClass : ITest

4. {

5.     public void TestMethod()

6.     {

7.         Console.WriteLine("TestClass.TestMethod");

8.     }

9. }

 

Program.cs

1. using System;

2. using System.Reflection;

3.

4. public class Program

5. {

6.     public static void Main()

7.     {

8.         Assembly assembly = Assembly.LoadFrom("TestClass.dll");

9.         Type type = assembly.GetType("TestClass");

10.         object instance = Activator.CreateInstance(type);

11.         ((ITest)instance).TestMethod();

12.     }

13. }

 

编译命令:

csc /t:library /out:TestClass.dll TestClass.cs ITest.cs

csc Program.cs ITest.cs

 

 


代码很简单,我们定义了一个公开的接口ITest,提供了一个实现该接口的类TestClass,然后在Program.cs通过发射创建TestClass的一个实例,然后调用ITest接口里面的一些方法。这是一个实现插件系统的最基本的操作, 但是当你执行编译生成出来的Program.exe的时候,程序抛出一个InvalidCastException

Unhandled Exception: System.InvalidCastException: Unable to cast object of type

'TestClass' to type 'ITest'.

   at Program.Main()

类的全名(或者说强签名)实际上包含Assembly完整名称的。

10.         object instance = Activator.CreateInstance(type);

11.         ((ITest)instance).TestMethod();


这两行,在CLR看来其实等于(分解成几步伪码):

 [TestClass,Version=0.0.0.0]ITest instance =  Activator.CreateInstance(type);
[Program, Version=0.0.0.0]ITest temp = ([Program, Version=0.0.0.0]ITest)instance;

Temp.TestMethod();


所以说,两个接口不是同一个接口。

 

但是如果在程序里面使用到两个不同的Assembly,并且这两个Assembly都包含名称相同的类,如果你的Winform程序里面需要寄宿WPF控件,或者反过来,你就经常会碰到这种问题,例如两种程序框架里面都包含TextBox类。当然啦,你可以说WPFWinform的类的命名空间不一样,只要在用的时候指定完整的命名空间就可以了,但是如果你碰到连命名空间都一样的情况下,或者说,如果你的程序同时引用到同一个Assembly的两个不同版本的文件,又如何解决呢?C#没有提供语法支持你在类名前面加上Assembly的名字虽然IL里面提供了对应的语法。

幸好,C#编译器csc.exe为我们提供了一个解决方案,csc.exe提供了一个参数/reference:<alias>=<file>可以让你为你程序所引用的一个Assembly指定别名,然后在源代码里面使用这个别名将名称重复的类改名,具体做法如下:

ITest.cs:

1. using System;

2.

3. public interface ITest

4. {

5.     void TestMethod();

6. }

 

TestClass.cs:

1. using System;

2.

3. public class TestClass : ITest

4. {

5.     public void TestMethod()

6.     {

7.         Console.WriteLine("TestClass.TestMethod");

8.     }

9. }

 

Program.cs

1. extern alias ITestDll;

2. using System;

3. using System.Reflection;

4.

5. public interface ITest

6. {

7.     void TestMethod();

8. }

9.

10. public class Program

11. {

12.     public static void Main()

13.     {

14.         Assembly assembly = Assembly.LoadFrom("TestClass.dll");

15.         Type type = assembly.GetType("TestClass");

16.         object instance = Activator.CreateInstance(type);

17.         ((ITestDll::ITest)instance).TestMethod();

18.     }

19. }

 

编译命令:

csc /t:library ITest.cs

csc /t:library /r:ITest.dll /out:TestClass.dll TestClass.cs

csc /r:ITestDll=ITest.dll Program.cs

 


这样就解决了类名重复的问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值