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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于“C”的问题不够具体,不清楚问题是指的是什么。如果是指计算机编程语言C,我可以回答如下: C是一种广泛用于编程的高级编程语言。C语言由贝尔实验室的丹尼斯·里奇(Dennis Ritchie)于1972年在UNIX操作系统上开发出来。C语言以其简洁、高效的特性而受到广大程序员的喜爱。 C语言的设计目标是提供一种可以进行底层操作的语言,同时又能保持较高的可移植性。C语言的语法简洁、结构化,易于学习和理解。它具有很强的灵活性,可以应用于各种类型的应用程序开发,包括系统软件、嵌入式系统、图形界面、网络编程等。C语言还可以与汇编语言进行混合编程,使得程序员可以更加精细地控制计算机硬件资源。 C语言的特色之一是其指针的使用,指针可以让程序员直接访问和操作内存地址,提高程序的效率。但指针的使用也容易引发内存错误,因此需要程序员对内存的管理非常谨慎。 C语言的标准库提供了丰富的函数和数据类型,方便程序员进行输入输出、字符串处理、内存分配等常用操作。此外,C语言还有许多第三方库可供使用,扩展了C语言的功能。 总之,C语言以其高效、灵活的特性成为了编程界的经典语言之一,许多现代编程语言都受到C语言的影响。学习和掌握C语言对于成为一名优秀的程序员是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值