我的一位同事不久前写了一段相当可疑的代码,最终它被打破了。这是简化的示例:
Assembly assembly = typeof(SmtpClient).Assembly;
Type _mailWriterType = assembly.GetType("System.Net.Mail.MailWriter"); //getting a reference to internal class
//create an instance of System.Net.Mail.MailWriter storing it into _mailWriter variable
//It's internal, but for now it still works
MethodInfo _sendMethod = typeof(MailMessage).GetMethod("Send",BindingFlags.Instance | BindingFlags.NonPublic);
//calling non-public method resulting in app crash
_sendMethod.Invoke(
message,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { _mailWriter, true },
null);
经过一番调查后发现,在我的开发机器上确实存在MailMessage.Send
方法的两个参数:
System.Net.Mime.BaseWriter writer
Boolean sendEnvelope
Hovewer,我们的QA工程师最近安装了VisualStudio 2012,并安装了.NET 4.5。因此,当QA人员尝试运行该应用程序时,他们获得了System.Reflection.TargetParameterCountException
。并且,看起来MailMessage.Send
在.NET 4.5中获得了第三个参数:
System.Net.Mime.BaseWriter writer
Boolean sendEnvelope
Boolean allowUnicode
当然,我们要重新实现这段代码以停止使用非公共接口。 Hovewer,我们的项目时间紧迫,所以我们现在买不起。
所以,这是一个问题:有没有办法通过反射来引用程序集的旧版本(例如.NET 4.0)?
答案 0 :(得分:3)
您可以使用typeof(SmtpClient).Assembly
加载程序集,而不是使用Assembly.Load(AssemblyName)
加载程序集。
AssemblyName
完整地描述了程序集的唯一标识。例如:
ExampleAssembly, Version=1.0.0.0, Culture=en, PublicKeyToken=a5d015c7d5a0b012
您可以在完整的程序集名称中指定版本控制信息。
Here是MSDN文档,包含更多示例。
答案 1 :(得分:0)
要具体,请执行此操作
var systemNet35 = Assembly.Load(
@"System.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL");
Type _mailWriterType = systemNet35.GetType("System.Net.Mail.MailWriter");
当然,这只适用于安装.Net 3.5。