簡體   English   中英

了解對象范圍基礎

[英]Understanding Object scope fundamentals

對於對象,我有一個基本的限制:當您創建“新”對象時,它將替換先前的對象。 如果是這樣,則將對象創建放在何處,以免在諸如while或For循環之類的重復調用中將其替換?

我正在研究一本C#書籍,並試圖使用多維數組作為我的表來創建通訊簿。 我的問題是每次創建“ New”數組時,先前的數據都會丟失... :-(

如果我將通訊簿對象移到另一個位置,則程序的其余部分找不到它。 所有有關面向對象設計的書都讓我感到困惑和沮喪。 希望您能闡明我的想法出了什么問題。 這是我的程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class Addressbook
{
    public string[,] fullname;
    public int cnt;
}

namespace ConsoleApp
{
    class MethodParams
    {
        public static void Main()
        {
            string myChoice;

            MethodParams mp = new MethodParams();
            do
            {                                
                // show menu and get input from user
                myChoice = mp.getChoice();

                // Make a decision based on the user's choice
                mp.makeDecision(myChoice);

                // Pause to allow the user to see the results
                Console.Write("press Enter key to continue...");
                Console.ReadLine();
                Console.WriteLine();
            } while (myChoice != "Q" && myChoice != "q"); // Keep going until the user wants to quit
        }
//*******************
        // show menu and get user's choice
        string getChoice()
        {
            string myChoice;
            // Print A Menu
            Console.WriteLine("My Address Book\n");
            Console.WriteLine("A - Add New Address");
            Console.WriteLine("D - Delete Address");
            Console.WriteLine("M - Modify Address");
            Console.WriteLine("V - View Addresses");
            Console.WriteLine("Q - Quit\n");
            Console.WriteLine("Choice (A,D,M,V,or Q): ");
            // Retrieve the user's choice
            myChoice = Console.ReadLine();
            return myChoice;
        }
//***********************
        // make decision
        void makeDecision(string myChoice)
        {
            Addressbook addrBk = new Addressbook();  //Create Addressbook Object
            addrBk.fullname = new string[10, 10];
            addrBk.fullname[0, 0] = "Tom";
            addrBk.fullname[0, 1] = "Nesler";
            addrBk.cnt = 1;
            switch (myChoice)
            {
                case "A":
                case "a":
                    Console.WriteLine("Enter First name");
            String FName;
                    FName =  Console.ReadLine();
            Console.WriteLine("Enter Last name");
                    String LName;
                    LName =  Console.ReadLine();
                    addrBk.fullname[addrBk.cnt,0] = FName;
                    addrBk.fullname[addrBk.cnt,1] = LName;
                    this.addAddress(ref addrBk);        //Input address name
                    addrBk.cnt = addrBk.cnt + 1;
                    break;

                case "V":
                case "v":
                    this.viewAddresses(ref addrBk);
                    break;
                case "Q":
                case "q":
                    Console.WriteLine("Bye.");
                    break;
                default:
                    Console.WriteLine("{0} is not a valid choice", myChoice);
                    break;
            }
        }
//*****************
        // insert an address
        void addAddress(ref Addressbook addrBk)  //Addr Object containing name and Address
        {
            Console.WriteLine("Name: {0} {1} added.", addrBk.fullname[addrBk.cnt, 0], addrBk.fullname[addrBk.cnt, 1]);
        }
//*****************
        // show addresses
        void viewAddresses(ref Addressbook addrBk)
        {
            Console.WriteLine("count is: {0}", addrBk.cnt);
           for (int i=0; i < addrBk.cnt; i++) 
            {
               Console.WriteLine("counter = {0}",i );
               Console.WriteLine("Name: {0} {1} ", addrBk.fullname[i,0], addrBk.fullname[i,1] );
            }
        }
    }

}
string a;   // this is a declaration - the variable `a` is null/nothing until 
            // you assign it a value

a = new String("Hello world");  // the variable `a` now references a String 
                                // Object that contains the string "Hello world"

a = new String("Good-bye World");  // the variable `a` now references a String 
                                   // Object that contains the string "Good-bye World" 

這是如何丟失對象的示例。 在過去,這被稱為內存泄漏。 在當今的托管代碼世界中,丟失的對象被“垃圾收集”拾起

實例化和對象時,通常將其傳遞給相似對象的一些集合以供以后參考。 可能是列表(地址)或字典(字符串,地址)。 這是對象“生存”的地方,直到集合本身超出范圍。

在您的程序內部,所有這些代碼都具有有限的生存期,即代碼的運行時間。 當程序結束時,這就是對象生存期的最終范圍。 這就是為什么我們擁有數據庫之類的東西,以便我們可以保存和恢復使用編程語言創建的想法的原因

我假設您想創建然后更新您的addrBk,因此示例中有幾個選項。 首先,您可以在Main方法中創建對象,然后將其傳遞給makeDecision方法:

public static void Main()
{
///...
    Addressbook addrBk = new Addressbook();
    addrBk.fullname = new string[10, 10];
    addrBk.fullname[0, 0] = "Tom";
    addrBk.fullname[0, 1] = "Nesler";
    addrBk.cnt = 1;

    do
    {
        // rest of code
        mp.makeDecision(addrBk, myChoice);
        // rest of code
    } //while ...
}
    void makeDecision(Addressbook addrBk, string myChoice)
    {
        switch (myChoice)
        //rest of code...
    }

您還可以在類中創建靜態對象,然后像在您的示例中一樣使用它,您可能不需要創建多個對象。 也請檢查其他fnostro答案,因為它可能使您對基本原理有更多的了解。

好像每次調用makeDecision()函數時都在創建一個新的Addressbook對象。 此外,您對通訊錄對象的唯一引用是通過此函數中的局部變量(addrBk)。 因此,當makeDecision函數退出時,您的代碼將不再具有查找通訊簿的任何方式。

至於此特定代碼的解決方案...有幾種解決方案。 最快的解決方案(但不一定是最整潔的解決方案)是采用makeDecision()函數的前5行並將其放在Main()函數的開頭。 然后,只需在每次調用時將addrBk變量作為參數傳遞給makeDecision()函數即可。

您可能會困惑的一件事與成員變量有關。 基本思想之一是,對象將其操作的數據與方法封裝在一起。 這意味着該數據可用於對象中的所有方法,而不必作為該方法的參數提供。 此數據存儲在成員變量中。

AddressBook為例,您可以看到它僅具有數據成員( fullnamecnt ),而沒有方法。 盡管如此,您的程序addAddress對通訊簿執行多項操作,例如addAddress向其添加地址,以及viewAddresses在控制台上顯示viewAddresses中的所有地址。

對於一個類,典型的是它同時包含數據和方法。 因此,在您的情況下(只需四處移動現有代碼,並在命名周內應用一些慣用的c#tweek):

public class Addressbook
{
    private string[,] _fullname;
    private int _cnt;

    public Addressbook()
    {
       // Questions:
       // Are 10 fields really needed for firstName and lastName?
       // What if a user adds more than 10 names.
        _fullname = new string[10, 10]; 
    }

    public void AddAddress(string firstName, string lastName)
    {
        _fullname[_cnt,0] = firstName;
        _fullname[_cnt,1] = lastName;
        Console.WriteLine("Name: {0} {1} added.", _fullname[_cnt, 0], _fullname[_cnt, 1]);
        _cnt = _cnt + 1;
    }

    public void ViewAddresses()
    {
        Console.WriteLine("count is: {0}", _cnt);
        for (int i=0; i < _cnt; i++) 
        {
           Console.WriteLine("counter = {0}",i );
           Console.WriteLine("Name: {0} {1} ", _fullname[i,0], _fullname[i,1] );
        }
    }
}

現在, AddressBook類可以執行以前可以做的所有事情,而MethodParams現在可以使用它,而無需確切地了解 AddressBook工作方式。 它只是需要知道什么可以做的。

現在,如果我們稍微更改class MethodParams以便為它提供一個通訊簿,事情就會變得容易得多:

class MethodParams
{
    private AddressBook _addressBook;

    public MethodParams(AddressBook addressBook)
    {
        _addressBook = addressBook; // this is the address book we will work with
    }

    public static void Main()
    {
        string myChoice;
        AddressBook theAddressBook = new AddressBook();

        MethodParams mp = new MethodParams(theAddressBook);
        do
        {                      
             // ... this can all stay the same.          
        } while (myChoice != "Q" && myChoice != "q"); // Keep going until the user wants to quit

        // When we get here, theAddressBook still contains everything.
        // We could save it to a file.
    }

    // ... see remarks for changes below.
}

現在,在您的makeDecision方法中,您可以執行以下操作以添加地址:

_addressBook.AddAddress(FName, LName);

並查看所有地址。

_addressBook.ViewAddresses();

我希望這有助於澄清一些事情。 以下是您在評論中提出的問題的答案:

這行public class Addressbook開始定義一個 ,它是一個類型 ,就像string是一個類型一樣。

此行private AddressBook _addressBook; 聲明一個名為_addressBook的私有成員變量 ,該變量的類型為AddressBook並且屬於MethodParams類。

在這一行中, AddressBook theAddressBook = new AddressBook(); 我們創建一個地址AddressBook類型的新對象實例 ,該對象實例被分配給名稱為theAddressBook的局部變量。

在這一行中, MethodParams mp = new MethodParams(theAddressBook); 我們創建類型的新對象實例MethodParams並通過其構造方法來初始化它public MethodParams(AddressBook addressBook) ,把它傳遞給指定的對象實例的引用theAddressBook作為命名方法參數方法參數 addressBook

在此行_addressBook = addressBook ,作為addressBook提供給構造函數的值(它是對我們在此代碼中先前創建的theAddressBook對象實例的引用)被分配給名為_addressBook的私有成員變量。 現在,當任何的方法MethodParams使用_addressBook ,比如像這樣_addressBook.AddAddress(FName, LName)它們與對象實例工作theAddressBook我們創建。

暫無
暫無

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

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