[問題記錄.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 的項目,已經能查看到編譯錯誤,如圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章