[问题记录.Dotnet]混用不同版本odp组件造成的System.MissingMethodException错误
某个项目遇到个ora的问题,打算先在开发环境中把托管odp组件更新为新的版本试一试。于是直接下载了新版本dll替换,但运行报错 System.MissingMethodException: 找不到方法:“xxxxx”。
甚是诡异,当下百思不得姐 (-_-!!! ...
静心打坐后试之,解开~~
【问题原因】
1. 基类使用的odp组件 和 派生类使用的组件版本不一致(基类项目引用改成了高版本odp后编译,但派生类的项目没有调整编译);
2. 派生类中操作基类中的 odp 对象(高版本),例如:
//基类定义了方法
protected Oracle.ManagedDataAccess.Client.OracleConnection GetConnection()
在基类里是 protected OracleConnectionV2 GetConnection()
在派生类里 OracleConnectionV1 = base.GetConnection(); //返回值类型是OracleConnectionV2
单独写了个验证程序:
1) 基类项目 ClassLibrary.dll
public class DbAccessBase
{
public string DBConnString { get; set; }
public DateTime GetDbTime()
{
object val;
using (OracleConnection conn = new OracleConnection(DBConnString))
{
conn.Open();
using (OracleCommand cmd = new OracleCommand("select sysdate from dual", conn))
{
val = cmd.ExecuteScalar();
}
}
return (DateTime)val;
}
protected OracleConnection GetConnection()
{
return new OracleConnection(DBConnString);
}
public string GetInfo()
{
return GetType().FullName + ", " + typeof(OracleConnection).Assembly.FullName;
}
}
2) 派生类项目ClassLibrary2.dll
public class DbAccess : ClassLibrary.DbAccessBase
{
public DateTime GetDbTime2()
{
object val;
using (OracleConnection conn = new OracleConnection(DBConnString))
{
conn.Open();
using (OracleCommand cmd = new OracleCommand("select sysdate from dual", conn))
{
val = cmd.ExecuteScalar();
}
}
return (DateTime)val;
}
public DateTime GetDbTime3()
{
object val;
using (OracleConnection conn = GetConnection())
{
conn.Open();
using (OracleCommand cmd = new OracleCommand("select sysdate from dual", conn))
{
val = cmd.ExecuteScalar();
}
}
return (DateTime)val;
}
public string GetInfo2()
{
return GetType().FullName + ", " + typeof(OracleConnection).Assembly.FullName;
}
}
3) 调用
private string Call(Func<DateTime> getDbTime)
{
try
{
return getDbTime().ToString();
}
catch (Exception ex)
{
return ex.ToString();
}
}
private void button1_Click(object sender, EventArgs e)
{
ClassLibrary2.DbAccess dbAccess = new ClassLibrary2.DbAccess();
dbAccess.DBConnString = txtDbConnString.Text;
txtOutput.Text = $"{dbAccess.GetInfo()}\r\n{dbAccess.GetInfo2()}\r\n------------\r\n";
//调用基类,高版本odp
txtOutput.Text += Call(dbAccess.GetDbTime) + "\r\n------------\r\n";
//调用派生类,低版本odp
txtOutput.Text += Call(dbAccess.GetDbTime2) + "\r\n------------\r\n";
//调用派生类,混用不同版本odp
txtOutput.Text += Call(dbAccess.GetDbTime3) + "\r\n------------\r\n";
}
private void btnPrintAssemblies_Click(object sender, EventArgs e)
{
Assembly[] array = AppDomain.CurrentDomain.GetAssemblies();
StringBuilder str = new StringBuilder();
foreach (Assembly item in array)
{
str.AppendLine($"{item.FullName}, {item.Location}");
}
txtOutput.Text += str.ToString() + "\r\n------------\r\n";
}
4) 重现方式:
a.先编译程序集 ClassLibrary.dll 和 ClassLibrary2.dll(都是引用低版本odp组件)
>>此时执行3)的代码是不报错的;
b.更改 ClassLibrary.dll 的引用,引用高版本的odp组件,重新编译生成 ClassLibrary.dll;
>>此时执行3)的代码就会报错
ClassLibrary2.DbAccess, Oracle.ManagedDataAccess, Version=4.122.19.1, Culture=neutral, PublicKeyToken=89b483f429c47342
ClassLibrary2.DbAccess, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342
------------
2020/1/13 11:38:56
------------
2020/1/13 11:38:56
------------
System.MissingMethodException: 找不到方法:“Oracle.ManagedDataAccess.Client.OracleConnection ClassLibrary.DbAccessBase.GetConnection()”。
在 ClassLibrary2.DbAccess.GetDbTime3()
在 WinFormsApp.Form1.Call(Func`1 getDbTime) 位置 E:\Users\fj\source\repos\OdpTest\RefTest\WinFormsApp\Form1.cs:行号 21
------------
其实这时打开 ClassLibrary2.dll 的项目,已经能查看到编译错误,如图: