【问题标题】:public Object from public method not visible in another public method in same class来自公共方法的公共对象在同一类的另一个公共方法中不可见
【发布时间】:2017-10-11 18:54:04
【问题描述】:

我是一个苦苦挣扎的新手,试图学习和了解这种新的 C# 语言和 OO 风格,我的大脑不像 20 年前那么敏锐。 这里我们有一个到 Access (.accdb) 的简单数据库连接 我正在实例化一个辅助类,它包含两个方法,即 makeconn 和 readfrondb 方法,如下所示

public void Form1_Load(object sender, EventArgs e)  {

        Clshelper chelp = new Clshelper();

        chelp.makeconn(); 
        chelp.readfromdb();

    }

这是下面的辅助类 - 创建是因为我想保留连接部分以及我在单独的方法中执行的任何类型的数据操作。 但是,除非在方法 makeconn 中创建连接对象 con1 的行抛出异常,因为 con1 是 NULL 对象,如果我将其编码如下。

public class Clshelper {
    public OleDbConnection con1;
    public OleDbCommand cmd;

    public Clshelper() {
        Console.WriteLine("instantiated Cls_helper()");
    }

    public void  makeconn() {   
       OleDbConnection con1 = new OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = D:\\DATA.accdb");
    }

    public void readfromdb() {

        con1.Open();
      (...)
      }

但是,如果我将 makeconn 中创建 con1 连接对象的行放入 readfromdb 的顶部,并且只运行 readfromdb 一切正常。 那么为什么 readfromdb 方法不能“看到”我在 makeconn 方法中创建的 con1 对象 - 我认为一个类中的任何变量对同一个类中的所有方法都是可见的?

【问题讨论】:

  • 只需将OleDbConnection con1 = new OleDbConnection(...) 更改为this.con1 = new OleDbConnection(...) 即可访问预期的属性。
  • 考虑使用一些命名约定来帮助您识别成员变量,例如 m_Con1 或 _con1 (实际上是基于使用什么约定的意见,但我建议使用不同于“简单名称”的名称" 用于局部变量/函数参数)
  • 您不应将数据库连接存储在字段(类级别变量)中。 ADO.NET 连接(如 OleDbConnection)实现 IDisposable 它们应该在 using 块中创建。
  • @mason,对于像Clshelper 这样的连接助手,将连接存储在成员变量中(并让类本身实现 IDisposable)可能是个好主意。我认为 .Net OleDbConnection 类的功能完全相同
  • @Gian Paolo(和其他人)会像我的助手这样的类在后台自动实现 iDisposable 还是我必须手动对其进行编码 - 基于标准,“使用”方法会更好吗?

标签: c# scope visibility public


【解决方案1】:

线

OleDbConnection con1 = // ...

实际上在makeconn 函数的范围内创建了一个全新的变量。虽然您有另一个名为 con1 的类范围变量,但它们是单独的变量,因此将值分配给一个(函数范围)变量不会将值分配给另一个(类范围)变量。

修复很简单。与其声明一个新变量,不如使用你已经在你的类中声明的那个:

public void  makeconn() {
   // Don't declare a new variable here:
   con1 = new OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = D:\\DATA.accdb");
}

有趣的旁注。如果你有一个与类作用域实例变量同名的函数作用域变量,你可以使用this关键字访问类作用域变量:

class MyClass {
    private int myVar = 1;

    private void myFunc(){
        int myVar = 2; // function-scoped myVar overrides class-scoped myVar

        int myOtherVar;

        myOtherVar = myVar; // myOtherVar = 2 (function-scoped myVar)
        myOtherVar = this.myVar; // myOtherVar = 1 (class-scoped myVar)
    }
}

【讨论】:

  • 非常感谢 JDB - 对我来说这是一个愚蠢的新手错误 - 或者当然 new 关键字是新变量/对象的声明。最初试图将连接方法创建为某种静态,因为它总是保持不变 - 但它让我失败了,所以我只是将所有内容都创建为公共 - 所以任何关于使连接对象或 makeconn 方法静态的建议都是受欢迎的改进- 很棒的社区
【解决方案2】:

您的助手类无法遵循有关处置连接的良好做法。最终,这可能会导致可用连接耗尽。当这种情况发生时,很难追查到。这就是为什么您在使用 IDisposable 对象时需要小心,以确保您已正确处理它们。

这是正确遵循此模式的一种方法:

public class ProductRepository
{
    private readonly string _connectionString;

    public MyRepository(string connectionString)
    {
        _connectionString = connectionString;
    }

    public List<Product> GetProducts()
    {
        using (var connection = new OleDbConnection(_connectionString))
        using (var command = new OleDbCommand("command text", connection))
        {
            connection.Open();
            //execute command and return results here
        }
    }

    public void AddProduct(Product product)
    {
        using (var connection = new OleDbConnection(_connectionString))
        using (var command = new OleDbCommand("command text", connection))
        {
            connection.Open();
            //execute command here
        }
    }
}

使用Dapper(此处未显示)可以进一步简化它,因此您不必创建命令对象并将结果映射到强类型类/从强类型类中映射。

【讨论】:

  • 感谢 mason - 1. 根据您的示例,推荐用于连接和命令对象,以及 2. 在行业/工作场所,是否可以使用“var con1”作为快捷方式而不是说"OleDbConnection con1"
  • 我专门用 using 语句展示了它,因为这是正确的做法。 using 语句将确保对象得到处理,即使有异常。您应该对几乎所有实现 IDisposable 接口的对象执行此操作。使用var 是不必显式编写类型的捷径,但您仍然具有完全的类型安全性。许多公司都有一种编码风格,规定什么时候可以使用,什么时候不能使用。学习使用它,所以如果你遇到它,你就会熟悉它。当你进入一家公司时,看看他们的偏好是什么。
  • @user35 你读过我给你链接的文档吗?
猜你喜欢
  • 2021-11-29
  • 1970-01-01
  • 2015-03-13
  • 2018-09-27
  • 2015-12-17
  • 2020-09-22
  • 2011-04-19
  • 2012-03-14
  • 1970-01-01
相关资源
最近更新 更多