Displaying all items in another class - c#

My problem is that I have a List<> variable connected to another class, and I want to get all the items from that List<> and put it into a string.
In the result string, i'd like to see callNum, copyNum, content, author, year, title
Here is where I'm trying to put it into a string
public class CItemControl
{
//declare a list variable
private List<CItem> mItems;
private CItem mNewItem;
//a method that instantiates the list
public CItemControl()
{
mItems = new List<CItem>();
}
//attribute to get all items
public List<CItem> Items
{
get { return mItems; }
}
public CItem NewItem
{
get { return mNewItem; }
}
//method to add item to the CItem list
public void AddItem(int callNum, int copyNum, string content, string author, string year)
{
mNewItem = new CItem(callNum, copyNum, content, author, year);
mItems.Add(mNewItem);
}
//method to return all items to a string
public CItem ListAllItems()
{
string allItems;
}
Here is the class where I'm trying to get the items from. There will be variables added later.
class CItem
{
//declare attributes
private string mTitle;
private string mAuthor;
private string mContent;
private string mYear;
private int mCopyNum;
private int mCallNum;
private bool mHold = false;
private bool mBorrowed = false;
private bool mShelf = false;
//overload a constructor
public CItem(int CallNum, int CopyNum, string Content, string Author, string Year)
{
callNum = CallNum;
copyNum = CopyNum;
content = Content;
author = Author;
year = Year;
}
//create the default constructor
public CItem()
{
callNum = 0;
copyNum = 0;
content = "";
author = "";
year = "";
}
//set attributes
public int callNum
{
get { return mCallNum; }
set { mCallNum = value; }
}
public string content
{
get { return mContent; }
set { mContent = value; }
}
public string author
{
get { return mAuthor; }
set { mAuthor = value; }
}
public string year
{
get { return mYear; }
set { mYear = value; }
}
public string title
{
get { return mTitle; }
set { mTitle = value; }
}
public int copyNum
{
get { return mCopyNum; }
set { mCopyNum = value; }
}
public bool hold
{
get { return mHold; }
}
public bool borrowed
{
get { return mBorrowed; }
}
public bool shelf
{
get { return mShelf; }
}
//display information for users
public string displayInfo()
{
return "Call Number: " + callNum + ". Copy Number: " + copyNum + ". Title: " + title +
". Author: " + author + ". Year Published: " + year + ". Content: " + content;
}
//new method to display status of item
public string displayStatus()
{
if (borrowed == true)
return "Item is currently being borrowed.";
if (shelf == true && hold == false)
return "Item is available for borrowing.";
else
return "Item is on hold";
}
Any help is much appreciated!
Thanks in advance.

ListAllItems shall look something like this
public string ListAllItems()
{
var sb = new StringBuilder(); // var is of type StringBuilder
mItems.ForEach(item => sb.Append(item.displayInfo());
return sb.ToString();
}

return String.Join("; ", allItems.Select(item => item.displayInfo()));

You don't provide a lot of informations on how and what informations you want in your result string.
Can't you achieve this objective with a simple loop ?
using System.Text;
(...)
public string ListAllItems()
{
StringBuilder allItems = new StringBuilder();
foreach(CItem itm in Items){
allItems.AppendLine(itm.displayInfo());
}
return allItems.ToString();
}
Stringbuilder is optional but is faster than string concatenation.

I don't normally like to add formatter methods to property bags like this. If you want the flexibility to change have many formatting implementations, you might want to make a seperate class do the formatting.
public interface IFormatter<in T>
{
string Format(T obj);
}
public class CItemFormatter : IFormatter<CItem>
{
public string Format(CItem item)
{
//formatting logic
}
}

Related

Why I cannot add Items into DataGrid in C#

I'm trying to dynamically add new records to DataGrid. I'm using HashSet to prevent duplicates. But when I want to add objects from HashSet to ObservableCollection, I get the error:
Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.IEnumerable<>.
I have implemented IEnumerable.
Constructor in AdminWindow.xaml.cs class:
public AdminWindow()
{
InitializeComponent();
ObservableCollection<Alert> alertToDataGrid = new ObservableCollection<Alert>();
for (int i = 0; i < Alert.alerts.Count; i++)
{
alertToDataGrid.Add(Alert.alerts[i]); //Here is the issue
}
AlertTable.ItemsSource = alertToDataGrid;
}
Alert class:
public class Alert : IEnumerable<Alert>
{
private string id;
private DateTime date;
private string email;
private string nameOfAlert;
private string typeOfAlert; // will be enum later
public static HashSet<Alert> alerts = new HashSet<Alert>();
public override string ToString()
{
return id + "\n" + Date+ "\n" + email + "\n" + nameOfAlert + "\n" + typeOfAlert;
}
public override bool Equals(object obj)
{
return obj is Alert alert &&
id == alert.id &&
Id == alert.Id;
}
public override int GetHashCode()
{
return HashCode.Combine(id, Id);
}
// Tried just to return Enumerator
public IEnumerator<Alert> GetEnumerator()
{
foreach (Alert alert in alerts)
{
yield return alert;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public Alert(string id, DateTime date , string email, string nameOfAlert, string typeOfAlert)
{
this.Id = id;
this.Date = date;
this.Email = email;
this.NameOfAlert = nameOfAlert;
this.TypeOfAlert = typeOfAlert;
}
public string Id { get => id; set => id = value; }
public string Email { get => email; set => email = value; }
public string NameOfAlert { get => nameOfAlert; set => nameOfAlert = value; }
public string TypeOfAlert { get => typeOfAlert; set => typeOfAlert = value; }
public DateTime Date { get => date; set => date = value; }
}
You could also try
foreach (Alert alert in Alert.alerts) {
alertToDataGrid.Add(alert);
}
See How can I enumerate through a HashSet? for more details
As mentioned, you can't use the indexing for a HashSet. If you're that insistent of using a HashSet, you can try alertToDataGrid.Add(Alert.alerts.ElementAt(i));. You'll need to have System.Linq included.
You cannot use [] i.e. indexing operator on HashSet as it is unordered data structure which does not support indexing. So it is not about DataGrid but about HashSet insterad of for loop please use foreach loop to iterate over HashSet or any other IEnumerable which does not support indexing.

calling methods and arrays objects Library Book console app C#

My professor wants us to create a reusable class and console app that lists book objects. I got the first part of the assignment where I am supposed to print the books I created, but now I am stuck on the part where I have to modify the data and print again using the same method and then check out two books and print again. I have tried to look at example online and although some of them have helped, none have been able to get me to pass this roadblock.
class LibraryBook
{
private string _bookTitle;
private string _authorName;
private string _publisher;
private int _copyrightYear;
private string _callNumber;
public LibraryBook(string booktitle, string authorname, string publisher, int ccyear, string callnumber)
{
BookTitle = booktitle;
AuthorName = authorname;
Publisher = publisher;
CopyrightYear = ccyear;
CallNumber = callnumber;
}
public string BookTitle
{
get
{
return _bookTitle;
}
set
{
_bookTitle = value;
}
}
public string AuthorName
{
get
{
return _authorName;
}
set
{
_authorName = value;
}
}
public string Publisher
{
get
{
return _publisher;
}
set
{
_publisher = value;
}
}
public int CopyrightYear
{
get
{
return _copyrightYear;
}
set
{
const int CYEAR = 2019;
if (value > 0)
_copyrightYear = value;
else
_copyrightYear = CYEAR;
}
}
public string CallNumber
{
get
{
return _callNumber;
}
set
{
_callNumber = value;
}
}
public bool Avail;
public void CheckOut()
{
Avail = true;
}
public void ReturnToShelf()
{
Avail = false;
}
public bool IsCheckedOut()
{
return Avail;
}
public override string ToString()
{
return $"Book Title: {BookTitle}{Environment.NewLine}" +
$"Author Name: {AuthorName}{Environment.NewLine}" +
$"Publisher: {Publisher}{Environment.NewLine}" +
$"Copyright Year: {CopyrightYear}{Environment.NewLine}" +
$"Call Number: {CallNumber}{Environment.NewLine}" +
$"Checked Out: {IsCheckedOut()}{Environment.NewLine}";
}
}
}
class Program
{
static void Main(string[] args)
{
LibraryBook[] favBooksArray = new LibraryBook[5];
favBooksArray[0] = new LibraryBook("Harry Potter and the Philospher's Stone", "J.K. Rowling", "Scholastic Corporation", 1997, "HA-12.36");
favBooksArray[1] = new LibraryBook("Harry Potter and the Chamber of Secret", "J.K. Rowling", "Scholastic Corporation", 2001, "HA-13.48");
favBooksArray[2] = new LibraryBook("Tangerine", "Edward Bloor", "Harcourt", 1997, "TB-58.13");
favBooksArray[3] = new LibraryBook("Roll of Thunder, Hear My Cry", "Mildred D. Taylor", "Dial Press", 1976, "RT-15.22");
favBooksArray[4] = new LibraryBook("The Giver", "Lois Lowry", "Fake Publisher", -1, "Fk200-1");
WriteLine($"------LIBRARY BOOKS------{Environment.NewLine}");
BooksToConsole(favBooksArray);
WriteLine($"------CHANGES MADE----- {Environment.NewLine}");
ChangesToBooks(favBooksArray);
BooksToConsole(favBooksArray);
WriteLine($"------RETURNING BOOKS TO SHELF------{Environment.NewLine}");
ReturnBooksToConsole(favBooksArray);
BooksToConsole(favBooksArray);
}
public static void BooksToConsole(LibraryBook[] favBooksArray)
{
foreach (LibraryBook books in favBooksArray)
{
WriteLine($"{books}{Environment.NewLine}");
}
}
public static void ChangesToBooks(LibraryBook[] favBooksArray)
{
favBooksArray[1].AuthorName = "*****The Rock*****";
favBooksArray[3].BookTitle = "****Totally Not A Fake Name*****";
favBooksArray[1].CheckOut();
favBooksArray[4].CheckOut();
}
public static void ReturnBooksToConsole(LibraryBook[] favBooksArray)
{
favBooksArray[1].ReturnToShelf();
favBooksArray[4].ReturnToShelf();
}
}
}

sort text file by property (e.g. .last_name)

I've searched StackOverflow for an answer to this, but can't find a clear answer.
I've this Player Class (Yes i've posted the class before)
namespace Tennis_Match
{
class Player
{
private string first_name;
private string middle_name;
private string last_name;
private DateTime dob;
private string nat;
private char gender;
public string First_name { get { return first_name; } set { first_name = value; } }
public string Middle_name { get {return middle_name; } set { middle_name = value; } }
public string Last_name { get { return last_name; } set { last_name = value; } }
public DateTime Dob { get { return dob; } set { dob = value; } }
public string Nat { get { return nat; } set { nat = value; } }
public char Gender { get { return gender; } set { gender = value; } }
public Player(string first_name, string last_name, string middle_name, DateTime dob, string nat, char gender)
{
this.first_name = first_name;
this.last_name = last_name;
this.middle_name = middle_name;
this.dob = dob;
this.nat = nat;
this.gender = gender;
}
public override string ToString()
{
return first_name + " " + middle_name + " " + last_name + " " + dob + " "+ nat + " " + gender;
}
public static int CalculateAge(DateTime dob)
{
int years = DateTime.Now.Year - dob.Year;
if ((dob.Month > DateTime.Now.Month) || (dob.Month == DateTime.Now.Month && dob.Day > DateTime.Now.Day))
years--;
return years;
}
private List<string> content = new List<string>();
public string FileName { get; set; }
public string Delimiter { get; set; }
private void Load()
{
TextFieldParser par = new TextFieldParser(FileName);
par.TextFieldType = FieldType.Delimited;
par.SetDelimiters(Delimiter);
while (!par.EndOfData)
{
string[] fields = par.ReadFields();
foreach (string field in fields)
{
Console.WriteLine(field);
}
}
par.Close();
}
public void RunReadCSVFile(string fn, string delim = "|")
{
FileName = fn;
Delimiter = delim;
Load();
}
public string GetLine(string fileName, int line)
{
using (var sr = new StreamReader(fileName))
{
for (int i = 1; i < line; i++)
sr.ReadLine();
return sr.ReadLine();
}
}
}
}
Then I've another class tournament. I want to sort a textfile by among other Last_name. I've got an idea that i might need to use IComparable to sort the file.
The file is structured like this:
1|Mariuss|Luka|Thygesen|1986-07-25|NAURU|NR
First you have nothing to sort. So add to class
static List<Player> players = new List<Player>();
Next you need to add items to List in following function
private void Load()
{
TextFieldParser par = new TextFieldParser(FileName);
par.TextFieldType = FieldType.Delimited;
par.SetDelimiters(Delimiter);
while (!par.EndOfData)
{
string[] fields = par.ReadFields();
foreach (string field in fields)
{
Console.WriteLine(field);
}
//-----------------------------Add -----------------------
Player newPlayer = new Player(fields[0], fields[1], fields[2], DateTime.Parse(fields[3]), fields[4], fields[5][0]);
players.Add(newPlayer);
}
par.Close();
}
Now you have something to sort. So add a sort method (or CompareTo())
public void Sort()
{
players = players.OrderBy(x => new { x.last_name, x.first_name, x.middle_name }).ToList();
}

Cant Figure out this c# reference

I was using the "this" keyword in my default constructor, below is the code in the class movie
namespace Movie_List
{ enum GenreType { Action, War, Drama, Thriller };
class Movie
{
//Data Members
private String _title;
private int _rating;
private GenreType _type;
//Properties
public GenreType GenType
{
get { return _type; }
set { _type = value; }
}
public String Title
{
get { return _title; }
set { _title = value; }
}
public int Rating
{
get { return _rating; }
set { _rating = value; }
}
public Movie()
: this("Jaws", GenreType.Action, 4) { }
public Movie(String title, GenreType type, int rating ) //working ctor
{
Title = title;
GenType = type;
Rating = rating;
}
public override string ToString()
{
return String.Format(" {0} Genre : {1}, Rating: {2:d} Stars. ", Title, GenType, Rating);
}
}
I wanted to read in from a text file so i used this code in the MainWindow.xaml.cs
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
string lineIn = "";
string[] filmarray;
using (StreamReader file = new StreamReader("filmlist.txt"))
{
while ((lineIn = file.ReadLine()) != null)
{
filmarray = lineIn.Split(new char[] { ',' });
moviecollection.Add(new Movie()
{
Title = filmarray[0],
GenType = (GenreType)Enum.Parse(typeof(GenreType), filmarray[1]),
Rating = Convert.ToInt32(filmarray[2]),
});
lstFilms.ItemsSource = moviecollection;
}
}
}
I dont need this bit of code now
: this("Jaws", GenreType.Action, 4)
But when i deleted it, the genre action and rating 0 stars still prints.
Why is this Happening does anyone know?
When you have this initialization:
Movie movie = new Movie();
the empty constructor
public Movie() : this("Jaws", GenreType.Action, 4) { }
calls the overloaded constructor which have several parameters:
public Movie(String title, GenreType type, int rating) { ... }
When you delete this line: this("Jaws", GenreType.Action, 4) { }, what is happening now is that you are only calling the empty constructor which does nothing at all.
So when you call
int ratingValue = movie.Rating;
the default value of integer which is zero is returned because you did set anything on it.
UPDATE
a simple if (maybe, if I understand what you mean)
Assuming Rating should be greater than zero.
public override string ToString()
{
if (Rating == 0)
{
return String.Format("{0}", Title);
}
else
{
return String.Format(" {0} Genre : {1}, Rating: {2:d} Stars. ", Title, GenType, Rating);
}
}
It's because enum and int are always initialized with default value of 0.
It's not like string - if you don't initialize it will equal null. If you want to emulate this behavior for int, you can always try using int? type.
To get more details on this subject take a look at Default Values Table (C#).

How to populate IEnumerable in Lambda expression?

I just cannot get this to work, would appreciate if someone can help.
So I get back an XML result from a database which looks like:
<matches>
<issuer client_name="MTR" score="6" match_list="MTR CORPORATION LIMITED"/>
<issuer client_name="PEOPLE''S REPUBLIC OF CHINA" score="4"
match_list="DEMOCRATIC PEOPLE'S REPUBLIC OF KOREA;GOVERNMENT OF THE
HONG KONG SPECIAL ADMINISTRATIVE REGION OF THE PEOPLE'S REPUBLIC OF
CHINA;MONGOLIAN PEOPLE'S REPUBLIC;PEOPLE'S DEMOCRATIC REPUBLIC OF
ALGERIA;PEOPLE'S REPUBLIC OF CHINA"/>
</matches>
From this XML I need to populate an object after doing some logic like matching the client_name I am getting back in the XML result to the one I have sent to database to get matches.
XDocument.Load(new StringReader(
row.GetString(row.GetOrdinal("xml_ret"))))))
.Single().Descendants("matches")
.Select(x =>
new Pool() {
Constituents = (IEnumerable<Constituent>)
//(... cannot work this how can IsReference populate)
//ClientName = x.Attribute("client_name").Value,
//Score = x.Attribute("score").Value,
//MatchList = x.Attribute("match_list").Value,
});
In a non-LINQ manner I can populate the object something like this:
foreach (Constituent constituent in pool.Constituents)
{
if (!string.IsNullOrEmpty(constituent.Name)
&& string.IsNullOrEmpty(constituent.Curve))
{
i++;
ConstituentMatch match = new ConstituentMatch();
ConstituentMatch.Group group =new ConstituentMatch.Group("High");
//High Match group
ICollection<string> curves = new List<string>();
curves.Add("EUR" + i);
curves.Add("USD" + i);
ICollection<string> names = new List<string>();
ConstituentMatch.Group.Entry entry =
new ConstituentMatch.Group.Entry(constituent.Name + " Ltd.",
curves);
group.Add(entry);
entry =
new ConstituentMatch.Group.Entry(constituent.Name + " Inc.",
curves);
group.Add(entry);
match.AddGroup(group);
}
}
But how can I do this using LINQ, as I am sure you can do it, I just cannot work it out.
The constituent class looks like:
public sealed class Constituent
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public ConstituentMatch Match {get;set;}
public Constituent(string name)
{
this.name = name;
}
public Constituent() : this(string.Empty) { }
}
And constituent match class looks like this:
public sealed class ConstituentMatch
{
private readonly Dictionary<string, Group> matches = new Dictionary<string, Group>();
public IEnumerable<string> GroupNames
{
get { return matches.Keys; }
}
public Group this[string name]
{
get { return matches[name]; }
}
public IEnumerable<Group> Groups
{
get { return matches.Values; }
}
public void AddGroup(Group group)
{
matches[group.Name] = group;
}
/// <summary>
/// Match group e.g. Poor, High, All, Begins With
/// </summary>
public sealed class Group
{
private readonly string name;
private readonly ICollection<Entry> matches = new List<Entry>();
public string Name
{
get { return name; }
}
public Group(string name)
{
this.name = name;
}
public void Add(Entry entry)
{
matches.Add(entry);
}
public override bool Equals(object obj)
{
bool result = false;
if (obj is Group)
{
Group other = obj as Group;
result = name == other.name;
}
return result;
}
public override int GetHashCode()
{
return name.GetHashCode();
}
public sealed class Entry
{
private string legalName;
private IEnumerable<string> curves;
private double notional = double.NaN;
private char seniriority = 'N';
public string LegalName
{
get { return legalName; }
}
public IEnumerable<string> Curves
{
get { return curves; }
}
public Entry(string legalName, IEnumerable<string> curves)
: this(legalName, curves, double.NaN, 'N') { }
public Entry(string legalName,
IEnumerable<string> curves,
double notional,
char seniriority)
{
this.legalName = legalName;
this.curves = curves;
this.notional = notional;
this.seniriority = seniriority;
}
}
}
}
Some thing similar to this should work
var haystack = new Pool().Constituents;
var indexedhaystack = haystack.Select((item, index)=> new {
item, index
});
var pool = new Pool()
{
Constituents = from l in indexedhaystack
select new Constituent()
{
//your stuff here
}
};
... extended ...
var constituents = new Pool().Constituents.Select((c, i) =>
new
{
Constituent = c,
Index = i
});
var items = from c in constituents
where !string.IsNullOrEmpty(c.Constituent.Name)
&& string.IsNullOrEmpty(c.Constituent.Curve)
let curves = new[]{
"EUR" + c.Index.ToString(),
"USD" + c.Index.ToString()
}
let match = new ConstituentMatch(){
new Group("High") {
new Entry(
c.Constituent.Name + " Ltd.",
curves),
new Entry(
c.Constituent.Name + " Inc.",
curves)
}
}
select new
{
Name = c.Constituent.Name,
Curves = curves,
Match = match
};
...
public class Constituent
{
public string Name { get; set; }
public string Curve { get; set; }
}
public class Pool
{
public List<Constituent> Constituents { get; set; }
}
public class Entry
{
public Entry(string entry, IEnumerable<string> curves)
{
}
}
public class Group : List<Entry>
{
public Group(string group) { }
}
public class ConstituentMatch : List<Group>
{
}
Language INtegrated Query is, as its name says, a technology for querying objects and data, not for modifying them.

Categories