简体   繁体   English

了解对象范围基础

[英]Understanding Object scope fundamentals

I have a fundamental block when it comes to objects: When you create a "new" object it replaces the prior one. 对于对象,我有一个基本的限制:当您创建“新”对象时,它将替换先前的对象。 If this is true, where to you put an object creation so that it does not get replaced in a repetitious call such as while or For loop? 如果是这样,则将对象创建放在何处,以免在诸如while或For循环之类的重复调用中将其替换?

I am working through a C# book and am trying to create an address book using a multidimensional array as my table. 我正在研究一本C#书籍,并试图使用多维数组作为我的表来创建通讯簿。 My problem is each time I create the "New" array, the prior data is lost...:-( 我的问题是每次创建“ New”数组时,先前的数据都会丢失... :-(

If I move the Addressbook Object to another location, the rest of the program can't find it. 如果我将通讯簿对象移到另一个位置,则程序的其余部分找不到它。 All the books on object oriented design leave me confused and frustrated. 所有有关面向对象设计的书都让我感到困惑和沮丧。 Hopefully you can shed some light on where I am going wrong in my thinking. 希望您能阐明我的想法出了什么问题。 Here is my program: 这是我的程序:

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" 

This is an example of how you can lose an object. 这是如何丢失对象的示例。 In the "old days" this was called a memory leak. 在过去,这被称为内存泄漏。 In today's world of managed code, the lost object is picked up by "garbage collection" 在当今的托管代码世界中,丢失的对象被“垃圾收集”拾起

When you instantiate and object, usually you pass it off to some collection of like objects for later reference. 实例化和对象时,通常将其传递给相似对象的一些集合以供以后参考。 Maybe a List(of Address) or a Dictionary(of String, Address). 可能是列表(地址)或字典(字符串,地址)。 this is where the object "lives" until the collection itself goes out of scope. 这是对象“生存”的地方,直到集合本身超出范围。

Inside of your program all of this code has a limited lifetime that is the run time of your code. 在您的程序内部,所有这些代码都具有有限的生存期,即代码的运行时间。 When your program ends, that is the final scope of an objects lifetime. 当程序结束时,这就是对象生存期的最终范围。 This is why we have things like databases so we can save and restore the ideas we create with programming languages 这就是为什么我们拥有数据库之类的东西,以便我们可以保存和恢复使用编程语言创建的想法的原因

I assume you want to have your addrBk created and then updated, so You have several options in your example. 我假设您想创建然后更新您的addrBk,因此示例中有几个选项。 First of all you can create your object inside Main method and then pass it to makeDecision method: 首先,您可以在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...
    }

You can also create static object in your class and then use it as in your example you probably don't need to create more than one object. 您还可以在类中创建静态对象,然后像在您的示例中一样使用它,您可能不需要创建多个对象。 Check also other fnostro answer as it may lead you to more understanding of fundamentals. 也请检查其他fnostro答案,因为它可能使您对基本原理有更多的了解。

Looks like you're creating a new Addressbook object each time the makeDecision() function is called. 好像每次调用makeDecision()函数时都在创建一个新的Addressbook对象。 Furthermore, the only reference you're keeping to the Addressbook object is via a local variable within this function (addrBk). 此外,您对通讯录对象的唯一引用是通过此函数中的局部变量(addrBk)。 Thus, when the makeDecision function exits, your code will no longer have any way of finding the address book. 因此,当makeDecision函数退出时,您的代码将不再具有查找通讯簿的任何方式。

As for a solution to this particular piece of code...there are several solutions. 至于此特定代码的解决方案...有几种解决方案。 The quickest solution (but not necessarily cleanest overall) would be to take the first 5 lines of your makeDecision() function and put them right at the beginning of the Main() function. 最快的解决方案(但不一定是最整洁的解决方案)是采用makeDecision()函数的前5行并将其放在Main()函数的开头。 Then simply pass the addrBk variable into the makeDecision() function as a parameter each time your call it. 然后,只需在每次调用时将addrBk变量作为参数传递给makeDecision()函数即可。

One of the things that you may be confused about relates to member variables. 您可能会困惑的一件事与成员变量有关。 One of the fundamental ideas is that an object encapsulates the data it operates on together with the methods. 基本思想之一是,对象将其操作的数据与方法封装在一起。 This means, that this data is available to all of the methods in an object, and don't have to be supplied as arguments to the method. 这意味着该数据可用于对象中的所有方法,而不必作为该方法的参数提供。 This data is stored in member variables. 此数据存储在成员变量中。

Taking your AddressBook example, you can see that it only has data members ( fullname and cnt ), but no methods. AddressBook为例,您可以看到它仅具有数据成员( fullnamecnt ),而没有方法。 Still, your program does perform several operations on an addressbook, like addAddress to add an address to it and viewAddresses to show all the addresses in the address book on the console. 尽管如此,您的程序addAddress对通讯簿执行多项操作,例如addAddress向其添加地址,以及viewAddresses在控制台上显示viewAddresses中的所有地址。

What would be typical for a class is that it contains both the data and the methods. 对于一个类,典型的是它同时包含数据和方法。 So in your case (just moving some of your existing code around, and applying some idiomatic c# tweeks to naming): 因此,在您的情况下(只需四处移动现有代码,并在命名周内应用一些惯用的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] );
        }
    }
}

The AddressBook class now can do everything it could before, and now MethodParams can use it without knowing exactly how the AddressBook does its thing. 现在, AddressBook类可以执行以前可以做的所有事情,而MethodParams现在可以使用它,而无需确切地了解 AddressBook工作方式。 It just needs to know what can be done. 它只是需要知道什么可以做的。

Now if we change the class MethodParams a bit so that we can give it an addressbook to work with, things become a lot easier: 现在,如果我们稍微更改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.
}

Now in your makeDecision method you can do the following, to add an address: 现在,在您的makeDecision方法中,您可以执行以下操作以添加地址:

_addressBook.AddAddress(FName, LName);

And this to view all addresses. 并查看所有地址。

_addressBook.ViewAddresses();

I hope this helps clarify a few things. 我希望这有助于澄清一些事情。 Here are some answers to your questions in the comments: 以下是您在评论中提出的问题的答案:

This line public class Addressbook starts the definition of a class , which is a type , just like string is a type. 这行public class Addressbook开始定义一个 ,它是一个类型 ,就像string是一个类型一样。

This line private AddressBook _addressBook; 此行private AddressBook _addressBook; declares a private member variable named _addressBook that is of the type AddressBook and belongs to the class MethodParams . 声明一个名为_addressBook的私有成员变量 ,该变量的类型为AddressBook并且属于MethodParams类。

In this line AddressBook theAddressBook = new AddressBook(); 在这一行中, AddressBook theAddressBook = new AddressBook(); we create a new object instance of type AddressBook that is assigned to the local variable with the name theAddressBook . 我们创建一个地址AddressBook类型的新对象实例 ,该对象实例被分配给名称为theAddressBook的局部变量。

In this line MethodParams mp = new MethodParams(theAddressBook); 在这一行中, MethodParams mp = new MethodParams(theAddressBook); we create a new object instance of the type MethodParams and initialize it through its constructor method public MethodParams(AddressBook addressBook) , passing it a reference to the object instance named theAddressBook as the method argument for the method parameter named addressBook . 我们创建类型的新对象实例MethodParams并通过其构造方法来初始化它public MethodParams(AddressBook addressBook) ,把它传递给指定的对象实例的引用theAddressBook作为命名方法参数方法参数 addressBook

In this line _addressBook = addressBook , the value supplied as addressBook to the constructor (which is a reference to the theAddressBook object instance that we created earlier in this code), is assigned to the private member variable named _addressBook . 在此行_addressBook = addressBook ,作为addressBook提供给构造函数的值(它是对我们在此代码中先前创建的theAddressBook对象实例的引用)被分配给名为_addressBook的私有成员变量。 Now when any of the methods in MethodParams use _addressBook , eg like this _addressBook.AddAddress(FName, LName) they are working with the object instance theAddressBook that we created. 现在,当任何的方法MethodParams使用_addressBook ,比如像这样_addressBook.AddAddress(FName, LName)它们与对象实例工作theAddressBook我们创建。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM