• [问题记录.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()}
    {dbAccess.GetInfo2()}
    ------------
    ";
        //调用基类,高版本odp
        txtOutput.Text += Call(dbAccess.GetDbTime) + "
    ------------
    ";
        //调用派生类,低版本odp
        txtOutput.Text += Call(dbAccess.GetDbTime2) + "
    ------------
    ";
        //调用派生类,混用不同版本odp
        txtOutput.Text += Call(dbAccess.GetDbTime3) + "
    ------------
    ";
    }
    
    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() + "
    ------------
    ";
    }

    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:Usersfjsource
    eposOdpTestRefTestWinFormsAppForm1.cs:行号 21
    ------------

    其实这时打开 ClassLibrary2.dll 的项目,已经能查看到编译错误,如图:

  • 相关阅读:
    【转】Dalvik虚拟机的启动过程分析
    【转】Android 之ActivityThead、ActivityManagerService 与activity的管理和创建
    【转】应用程序的入口是ActivityThread
    【转】Android中Application类用法
    【转】360浏览器极速与兼容模式的解释
    操作系统学习(七)--操作系统之外设显示器和键盘
    操作系统学习(六)-- 虚拟内存(页面置换算法)
    操作系统学习(五)-- 操作系统之内存管理
    操作系统学习(四)-- 操作系统之进程同步和死锁
    数据库系统学习(八)-SQL语言与数据库完整性和安全性
  • 原文地址:https://www.cnblogs.com/fj365/p/13295438.html
Copyright © 2020-2023  润新知