[问题记录.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 的项目,已经能查看到编译错误,如图:

posted @ 2020-01-13 13:23  俊哥V  阅读(160)  评论(0编辑  收藏  举报