Reputation: 6490
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.
Upvotes: 2
Views: 2685
Reputation: 15931
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);
}
Upvotes: 3
Reputation: 4344
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());
}
Upvotes: 2
Reputation: 2888
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>
}
}
Upvotes: 1