Displaying objects using foreach loop

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-04 07:52:11

问题


I am having a problem while retrieving data from an ArrayList and displaying them into textboxs. I am getting an error: Unable to cast object of type 'Lab_9.Book' to type 'Lab_9.Magazine'. I tried use 2 foreach loops but that seems to be out of the question. How could I avoid this problem?

Problem occurs here:

    // Displaying all Book objects from pubs ArrayList.
    foreach (Book list in pubs)
    {
        bookNumber++; // Count books from the begining.

        // Displaying and formating the output 
        // in txtBookList textbox.
        bookList.txtBookList.Text +=
            "=== Book " + bookNumber + " ===" + Environment.NewLine +
            list.Title + Environment.NewLine +
            list.getAuthorName() + Environment.NewLine +
            list.PublisherName + Environment.NewLine +
            "$" + list.Price + Environment.NewLine
            + Environment.NewLine;
    }

Regards.


回答1:


The items of your pub object(ArrayList) are Object type instances for Book and Magazine types. So you need to filter using .OfType() to display each type. This method will returns only the instances of the target type(T) in ArrayList.

foreach (Book list in pubs.OfType<Book>())
{
}

foreach (Magazine list in pubs.OfType<Magazine>())
{
}

To combine the two foreach, I will suggest you to override ToString() or to make a base class having the string property. For using the base class, set all of values(eg title + "," + bookNumber...) to the string property. I will show you overriding ToString().

internal class Book
{
    public override string ToString()
    {
        return "=== Book " + bookNumber + " ===" + Environment.NewLine +....;
    }
}

internal class Magazine
{
    public override string ToString()
    {
        return "=== Publication: " + bookNumber + ....;
    }
}

And then you can combine the two loop.

foreach (string item in pub)
{
    Console.WriteLine(item.ToString());
}



回答2:


this will allow you to only have a single loop, but it's not pretty

foreach (object publication in pubs)
{
   var book = publication as Book;
   var magazine = publication as Magazine;
   if (book != null) {
     //it's a book, do your thing
   } else if (magazine != null) {
     //it's a magazine, do your thing
   } else {
    throw new InvalidOperationException(publication.GetType().Name + " is not a book or magazine: ");
   }
}

Instead of inheritance, you really want to define an interface that encapsulates the common properties and methods of all publications.

public interface IPublication
{
  string Title {get;set;}
  float Price {get;set;}
  // etc.
}

Next have your classes implement the interface

public class Book : IPublication
{
  public string Title {get;set;}
  public float Price {get;set;}
  //the rest of the book implementation
}

public class Magazine: IPublication

{
  public string Title {get;set;}
  public float Price {get;set;}
  //the rest of the magazine implementation
}

you've got a lot more flexibility at this point, but for your purposes you can keep the rest of the code as is and use just a single loop that is much cleaner, and more inline with jwJung's solution

foreach (var publication in pubs.OfType<IPublication>())
{
  // publication is either a book or magazine, we don't care we are just interested in the common properties
  Console.WriteLine("{0} costs {1}",  publication.Title, publication.Price);
}



回答3:


Edit: I've re-read your question, and your comment (sorry about that), I think what you're looking for this:

foreach (var list in pubs)
{
    if(list is Book)
    {
        Book tmp = (Book)list;
        // Print tmp.<values> 
    }

    if(list is Magazine)
    { 
        Magazine tmp = (Magazine)list;
        // Print tmp.<values>         
    }
} 


来源:https://stackoverflow.com/questions/7990883/displaying-objects-using-foreach-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!