簡體   English   中英

C#如何在另一個方法中提供對象?

[英]C# How to have an object available in another method?

我有兩種方法,在ConnecttoDB方法中,我創建了一個名為connection的對象,但是在第二種方法中我需要該對象來指定SQLiteCommand。 我如何擁有該對象在InsertField方法中可用?

public class Database
{
    private static string _datasource;
    private static string _table;
    private static string _field;
    private static string _values;

    public static void ConnecttoDB(string datasource)
    {
        _datasource = datasource;
        SQLiteConnection connection = new SQLiteConnection();
        connection.ConnectionString = "Data Source: " + _datasource;
        connection.Open();
    }
    public static void InsertField(string table, string field, string values)
    {
        SQLiteCommand command = new SQLiteCommand(/*connection*/);

        _table = table;
        _field = field;
        _values = values;
        String.Format("INSERT INTO {0} {1} VALUES{2}", _table, _field, _values);
    }
}

你的班級設計很奇怪。 為什么沒有明顯的原因_values _table_field_values聲明為類字段,卻不為connection這樣做,這將解決您的問題? 您可以直接使用tablefieldvalues參數,而無需事先將它們分配給字段。

讓我建議另一種方法:

public class Database
{
    private string _connectionString;

    // Pass the datasource through the constructor.
    public Database(string datasource)
    {
        _connectionString = "Data Source: " + datasource;
    }

    public void InsertField(string table, string field, object value)
    {
        using (var conn = new SQLiteConnection(_connectionString)) {
            string sql = String.Format("INSERT INTO {0} ({1}) VALUES (@1)",
                                       table, field);
            var command = new SQLiteCommand(sql, conn);
            command.Parameters.AddWithValue("@1", value);
            conn.Open();
            command.ExecuteNonQuery();
        }
    }
}

(未經測試,SQLite的調用約定可能有所不同)

我正在使用與任何類型兼容的valueobject類型。 我也將此值作為命令參數傳遞給命令。 這樣,例如, DateTime值將自動轉換為SQLite的正確格式。 它還可以防止SQL注入 (我希望表名和字段名由應用程序定義,而不是由用戶輸入。)

由於存在連接池,系統會保持連接打開一段時間,並自動重用打開的連接。 因此, connection.Open(); 每次調用時,call並不會真正從物理上重新打開連接。 另一方面,這種方法可防止連接打開很長時間並且不使用系統資源。

using語句自動負責關閉連接並處置連接所使用的資源-即使在代碼塊到達其末尾之前發生異常時也是如此。

您可以像這樣使用它:

var db = new Database("my data source");
db.InsertField("myTable", "myField", 100);

更新

如果您需要可變數量的參數,則可以將數組用於字段和值:

public void InsertField(string table, string[] fields, object[] values)
{
    if (fields.Length != values.Length) {
        throw new ArgumentException(
            "The fields and values arrays must have the same length");
    }

    string fieldNames = String.Join(", ", fields); // ==> "name1, name2, name3"

    // ==> "@p0, @p1, @p2"
    string paramNames = String.Join(", ",
        Enumerable.Range(0, fields.Length)
            .Select(i => "@p" + i)
            .ToArray()
    );
    using (var conn = new SQLiteConnection(_connectionString)) {
        string sql = String.Format("INSERT INTO {0} ({1}) VALUES ({2})",
                                   table, fieldNames, paramNames);
        var command = new SQLiteCommand(sql, conn);
        for (int i = 0; i < values.Length; i++) {
            command.Parameters.AddWithValue("@p" + i, values[i]);
        }
        conn.Open();
        command.ExecuteNonQuery();
    }
}

用法:

var db = new Database("my data source");
db.InsertField("myTable", 
               new string[]{ "Name", "Quantity", "Price", "Date" }, 
               new object[]{ "Apples", 12, 2.65m, DateTime.Now });

要解決您當前面臨的問題:

在這種情況下,您實際上不應該這樣做。 您的兩種方法應該是一種方法:

public static void InsertField(string table, string field, string values)
{
    using (SQLiteConnection connection = new SQLiteConnection())
    {
        using (SQLiteCommand command = new SQLiteCommand(connection))
        {
            _table = table;
            _field = field;
            _values = values;
            String.Format("INSERT INTO {0} {1} VALUES{2}", _table, _field, _values);
            // and the rest of the code, incomplete in the example
        }
    }
}

建立一個SQL連接對象並不是一個昂貴的過程。 而且只有一行代碼。 因此,通過將其卸載到另一種方法實際上並沒有節省太多。 但是,您正在做的事情是引入了許多其他潛在的運行時問題(與您當前遇到的容易看到的編譯時問題相對),例如資源泄漏和已處置對象錯誤。

將連接和命令對象封裝得盡可能接近其用法,並在完成處理后盡快處理它們。 對基礎系統進行了很好的優化,可以在您再次需要使用另一種方法(或再次調用相同的方法)時重新創建它們。

要從字面上解決您的問題:

考慮從一個方法傳遞給另一方法的變量的范圍,方法的范圍等。您可以選擇。

變量是方法所在的對象的屬性嗎? 例如,在一個Person對象中,您可能有一個稱為Height東西。 既然描述了這個人,那么它可以是類級別的:

public int Height { get; private set; }

public void OneMethod(int someValue)
{
    // more code
    Height = someValue;
    // more code
}

public void AnotherMethod()
{
    // more code
    someOtherObject.DoSomethingWithHeight(Height);
    // more code
}

如果該值實際上未描述對象,而是在較小的范圍內,請考慮將其傳遞給方法。 也許像:

public void SomeMethod()
{
    // more code
    var someValue = 123;
    // more code
    AHelperMethod(someValue);
    // more code
}

private void AHelperMethod(int aValue)
{
    // more code
    someOtherObject.DoSomethingWithValue(aValue);
    // more code
}

在第一種情況下,這兩種方法都是使用描述該對象的屬性對對象本身執行某些操作。 在第二種情況下,第二種方法只是對象內部的某種東西,僅用於支持第一種方法的高級操作。 在第一種方法中,它可能只是內聯代碼,但出於重用,可讀性,保持抽象級別或許多重構原因,它已被提取到其自己的方法中。

將連接作為私有實例字段使用,然后可以在所有方法中使用它。 同時刪除靜態關鍵字。 很少使用靜態,並且通常很糟糕。

public class Database
{
    private string _datasource;
    private string _table;
    private string _field;
    private string _values;
    private SQLiteConnection _connection;

    public void ConnecttoDB(string datasource)
    {
        _datasource = datasource;
        _connection = new SQLiteConnection();
        _connection.ConnectionString = "Data Source: " + _datasource;
        _connection.Open();
    }
    public void InsertField(string table, string field, string values)
    {
        SQLiteCommand command = new SQLiteCommand(_connection);

        _table = table;
        _field = field;
        _values = values;
        String.Format("INSERT INTO {0} {1} VALUES{2}", _table, _field, _values);
    }
}

您可以全局保留它,也可以將其作為參數傳遞給InsertFields。 在后一種情況下,您必須在某個地方創建它,然后將其傳遞給Your方法。

最簡單的方法是將SQLiteConnection對象聲明為類級變量。 然后,您的InsertField方法將使用類級別變量,如下所示:

SQLiteCommand命令=新的SQLiteCommand(連接);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM