0

The solution consists of three classes: the SongGenre, the Song and the Library (+ Program). I am just following the instructions so most of coding comes from my lectures and the book and not much of the experience. It is what what you see and I am not really proud of it. Pointers are really appreciated. The main one is why the enum values can not be seen in another classes?
This code has been fixed (see comments).

   namespace SongLibrary
   {      
      [Flags]
      enum SongGenre
      {            
          Unclassified = 0,
          Pop = 0b1,
          Rock = 0b10,
          Blues = 0b100,
          Country = 0b1_000,
          Metal = 0b10_000,
          Soul = 0b100_000
       }
    }
  
namespace SongLibrary
{
    /*This acts like a record for the song. The setter is missing for all the properties.
     * There are no fields.
     * This class comprise of four auto-implemented properties with public getters and 
     * setters absent. */
    public class Song
    {
        public string Artist { get; }
        public string Title { get; }
        public double Length { get; }
        public SongGenre Genre { get; }

        /*This constructor that takes four arguments and assigns them to the appropriate  properties.*/
        public Song(string title, string artist, double length, SongGenre genre)
        {
            Artist = artist;
            Title = title;
            Length = length;            
            SongGenre Genre = SongGenre.genre;/*<-ERROR 'SongGenre does not contain a definition for 'genre'*/
        }
        public override string ToString()
        {
            return string.Format("[{0} by ,{1} ,({2}) ,{3}min]", Title, Artist, Genre, Length);
        }
     }
  }
   namespace SongLibrary
   {
    public static class Library
    {
        /*This is a static class therefore all the members also have to be static. Class members 
         * are accessed using the type instead of object reference.
         * There are no properties.
         * There is no constructor for this class.
         * There are four over-loaded methods. */

        /*This private field is a list of song object is a class variable.*/
        private static List<string> songs = new List<string> { "title", "artist", "length", "genre" };

        /*This is a public class method that does not take any argument and displays all the songs in 
         * the collection.*/
        public static void DisplaySongs()
        {
            for (int i = 0; i < songs.Count; i++)
                Console.WriteLine(songs[i]);
        }
        /*This is a public class method that takes a double argument and displays only songs that are 
         * longer than the argument.*/
        public static void DisplaySongs(double longerThan)
        {
            foreach (string songs in songs)
            {
                if (songs.Length > longerThan)
                {
                    Console.WriteLine("\n" + songs);
                }
            }
        }
        /*This is a public class method that takes a SongGenre argument and displays only songs that 
         * are of this genre.*/
        public static void DisplaySongs(SongGenre genre)
        {
            foreach (string songs in songs)
            {
                if (songs.Genre == genre)/*<-ERROR 'string' does not contain a definition for 'Genre'
                                          * and no accessable extension method 'Genre' accepting a first
                                          * argument of type 'string' could be found*/
                {
                    Console.WriteLine("\n" + songs);
                }
            }
        }
        /*This is a public class method that takes a string argument and displays only songs by this artist.*/
        public static void DisplaySongs(string artist)
        {
            foreach (string songs in songs)
            {
                if (songs.Artist == artist) /*< -ERROR 'string' does not contain a definition for 'Artist'
                                            * and no accessable extension method 'Artist' accepting a first
                                            * argument of type 'string' could be found */
                {
                    Console.WriteLine("\n" + songs);
                }
            }
        }

        /*This a class method that is public. It takes a single string argument that represents a text file containing 
         * a collection of songs. You will read all the data and create songs and add it to the songs collection.You 
         * will have to read four lines to create one Song. Your loop body should have four ReadLine(). */
        public static void LoadSongs(string fileName)
        {
            /*Initialize the songs field to a new List of Song*/
            List<string> songs = new List<string> { "title", "artist", "length", "genre" };

            /*Declare four string variable (title, artist, length, genre) to store the results of four in reader.ReadLine().*/
            string title;
            string artist;
            double length;
            SongGenre genre;

            /*The first ReadLine() is a string representing the title of the song. This can and should be used as a check 
             * for termination condition. If this is empty then there are no more songs to read i.e. it is the end of 
             * the file. The next ReadLine() will get the Artist. The next ReadLine() will be a string that represents 
             * the weight. Use the Convert.ToDouble to get the required type. The next ReadLine() will be a string that 
             * represents the genre. Use the Enum.Parse() to get the required type. Use the above four variables to create 
             * a Song object. Add the newly created object to the collection.And finally do one more read for the title 
             * to re-enter the loop.*/

            TextReader reader = new StreamReader(filename);//<-ERROR The name 'filename' does not exist in the current context
            string line = reader.ReadLine();
            while (line != null)
            {
                string[] data = line.Split();
                title.Add(data[0]);//<-ERROR Use of unassigned local variable 'title'| 'string' does not contain definition for 'Add'
                artist.Add(data[1]);//<-ERROR Use of unassigned local variable 'artist'| 'string' does not contain definition for 'Add'
                length.Add(Convert.ToDouble(data[2]));/*<-ERROR Use of unassigned local variable 'length'| 'string' does not contain 
                                                       * definition for 'Add'*/
                genre.Add(Enum.Parse(data[3]));/*<-ERROR Use of unassigned local variable 'genre' |ERROR 'string' does not contain 
                                                * definition for 'Add' | ERROR The type arguments for method Enum.Parse cannot be 
                                                inferred from the usage*/                
                line = reader.ReadLine();
            }
            reader.Close();
        }
    }   
 }
class Program
    {        
        static void Main(string[] args)
        {
            List<string> songs = new List<string>();
            string filename = @"D:\songs4.txt";//<-Warning The variable 'filename' is assigned but it's value never used.

            //To test the constructor and the ToString method
            Console.WriteLine(new Song("Baby", "Justin Bebier", 3.35, SongGenre.Pop));//<-ERROR 'Pop'

            //This is first time to use the bitwise or. It is used to specify a combination of genres
            Console.WriteLine(new Song("The Promise", "Chris Cornell", 4.26, SongGenre.Country | SongGenre.Rock));//<-ERROR 'Country' and 'Rock'

            Library.LoadSongs("songs4.txt");     //Class methods are invoke with the class name
            Console.WriteLine("\n\nAll songs");
            Library.DisplaySongs();

            SongGenre genre = SongGenre.Rock;//<-ERROR 'SongGenre' does no contain a definition for 'Rock'
            Console.WriteLine($"\n\n{genre} songs");
            Library.DisplaySongs(genre);

            string artist = "Bob Dylan";
            Console.WriteLine($"\n\nSongs by {artist}");
            Library.DisplaySongs(artist);

            double length = 5.0;
            Console.WriteLine($"\n\nSongs more than {length}mins");
            Library.DisplaySongs(length);

            Console.ReadKey();
        }
    }
}

song4.txt file is used to test the solution:

Baby
Justin Bebier
3.35
Pop
Fearless
Taylor Swift
4.03
Pop
Runaway Love
Ludacris
4.41
Pop
My Heart Will Go On
Celine Dion
4.41
Pop
Jesus Take The Wheel
Carrie Underwood
3.31
Country
If Tomorrow Never Comes
Garth Brooks
3.40
Country
Set Fire To Rain
Adele
4.01
Soul
Don't You Remember
Adele
3.03
Soul
Signed Sealed Deliverd I'm Yours
Stevie Wonder
2.39
Soul
Just Another Night
Mick Jagger
5.15
Rock
Brown Sugar
Mick Jagger
3.50
Rock
All I Want Is You
Bono
6.30
Metal
Beautiful Day
Bono
4.08
Metal
Like A Rolling Stone
Bob Dylan
6.08
Rock
Just Like a Woman
Bob Dylan
4.51
Rock
Hurricane
Bob Dylan
8.33
Rock
Subterranean Homesick Blues
Bob Dylan
2.24
Rock
Tangled Up In Blue
Bob Dylan
5.40
Rock
Love Me
Elvis Presley
2.42
Rock
In The Getto
Elvis Presley
2.31
Rock
All Shook Up
Elvis Presley
1.54
Rock

The output should look like that:

Baby by Justin Bebier (Pop) 3.35min
The Promise by Chris Cornell (Rock, Country) 4.26min
All songs
Baby by Justin Bebier (Pop) 3.35min
Fearless by Taylor Swift (Pop) 4.03min
Runaway Love by Ludacris (Pop) 4.41min
My Heart Will Go On by Celine Dion (Pop) 4.41min
Jesus Take The Wheel by Carrie Underwood (Country) 3.31min
If Tomorrow Never Comes by Garth Brooks (Country) 3.40min
Set Fire To Rain by Adele (Soul) 4.01min
Don't You Remember by Adele (Soul) 3.03min
Signed Sealed Deliverd I'm Yours by Stevie Wonder (Soul) 2.39min
Just Another Night by Mick Jagger (Rock) 5.15min
Brown Sugar by Mick Jagger (Rock) 3.50min
All I Want Is You by Bono (Metal) 6.30min
Beautiful Day by Bono (Metal) 4.08min
Like A Rolling Stone by Bob Dylan (Rock) 6.08min
Just Like a Woman by Bob Dylan (Rock) 4.51min
Hurricane by Bob Dylan (Rock) 8.33min
Subterranean Homesick Blues by Bob Dylan (Rock) 2.24min
Tangled Up In Blue by Bob Dylan (Rock) 5.40min
Love Me by Elvis Presley (Rock) 2.42min
In The Getto by Elvis Presley (Rock) 2.31min
All Shook Up by Elvis Presley (Rock) 1.54min


Rock songs
Just Another Night by Mick Jagger (Rock) 5.15min
Brown Sugar by Mick Jagger (Rock) 3.50min
Like A Rolling Stone by Bob Dylan (Rock) 6.08min
Just Like a Woman by Bob Dylan (Rock) 4.51min
Hurricane by Bob Dylan (Rock) 8.33min
Subterranean Homesick Blues by Bob Dylan (Rock) 2.24min
Tangled Up In Blue by Bob Dylan (Rock) 5.40min
Love Me by Elvis Presley (Rock) 2.42min
In The Getto by Elvis Presley (Rock) 2.31min
All Shook Up by Elvis Presley (Rock) 1.54min


Songs by Bob Dylan
Like A Rolling Stone by Bob Dylan (Rock) 6.08min
Just Like a Woman by Bob Dylan (Rock) 4.51min
Hurricane by Bob Dylan (Rock) 8.33min
Subterranean Homesick Blues by Bob Dylan (Rock) 2.24min
Tangled Up In Blue by Bob Dylan (Rock) 5.40min


Songs more than 5mins
Just Another Night by Mick Jagger (Rock) 5.15min
All I Want Is You by Bono (Metal) 6.30min
Like A Rolling Stone by Bob Dylan (Rock) 6.08min
Hurricane by Bob Dylan (Rock) 8.33min
Tangled Up In Blue by Bob Dylan (Rock) 5.40min
Alan Shore
  • 103
  • 1
  • 9

1 Answers1

1

There are a couple of different bits wrong with it and it'll take a little while to work through with some explanations, but the basic problem (that you pointed me to here from your question) of "Genre can't be seen in other classes" is that the Genre enum is declared inside a class called SongGenre rather than being declared in the namespace directly, and you're hence not referring to it properly (it's of type SongGenre.Genre, not Genre) so in the Song class (for example) you'd declare like:

public SongGenre.Genre Genre { get; }
       ^^^^^^^^^^^^^^^ ^^^^^
     this is the type   the name

Consequentially this is a bit of a syntax error in the Song contructor:

SongGenre Genre = SongGenre.genre;/*<-ERROR 'SongGenre does not contain a definition for 'genre'*/

It should be like:

Genre = SongGenre.Genre.Blues;

Or like:

Genre = genre;

But then you have to adjust your constructor not to take a SongGenre class but to take a SongGenre.Genre enum:

public Song(string title, string artist, double length, SongGenre.Genre genre)

It's actually causing you a lot of headaches by having that enum inside the SongGenre class. You should consider throwing the SongGenre class away and moving the enum into the namespace directly, instead and renaming the enum to be SongGenre:

namespace whatever{

  enum SongGenre{ Blues...

This means you don't have to refer to it by the class name prefix all the time and your existing code will work more like expected


You have another type confusion here:

                if (songs.Genre == genre)/*<-ERROR 'string' does not contain a definition for 'Genre'
                                          * and no accessable extension method 'Genre' accepting a first
                                          * argument of type 'string' could be found*/
                {
                    Console.WriteLine("\n" + songs);
                }

songs is a list of strings, not a list of Songs, and strings don't have a Genre property. Try List<Song> instead


= new List<string> { "title", "artist", "length", "genre" };

This doesnt need to make sense to me; are you expecting these to be column headers to somthing? This just declares a list of 4 strings, nothing really to do with songs. You could perhaps load these strings into a combo box so the user can "choose a thing to search by" - but they aren't anything to do with songs


title.Add(data[0]);//<-ERROR Use of unassigned local variable 'title'| 'string' does not contain definition for 'Add'

title is a string, not a list or other container, and it cannot be added to


TextReader reader = new StreamReader(filename);//<-ERROR The name 'filename' does not exist in the current context
            string line = reader.ReadLine();
            while (line != null)
            {
                string[] data = line.Split();
                title.Add(data[0]);//<-ERROR Use of unassigned local variable 'title'| 'string' does not contain definition for 'Add'
                artist.Add(data[1]);//<-ERROR Use of unassigned local variable 'artist'| 'string' does not contain definition for 'Add'
                length.Add(Convert.ToDouble(data[2]));/*<-ERROR Use of unassigned local variable 'length'| 'string' does not contain 
                                                       * definition for 'Add'*/
                genre.Add(Enum.Parse(data[3]));/*<-ERROR Use of unassigned local variable 'genre' |ERROR 'string' does not contain 
                                                * definition for 'Add' | ERROR The type arguments for method Enum.Parse cannot be 
                                                inferred from the usage*/                
                line = reader.ReadLine();
            }
            reader.Close();

If I was reading that file I'd do it like:

//read all lines into an array
var songFile = File.ReadAllLines("...path to file...");

List<Song> library = new List<Song>();

//iterate, skipping 4 lines at a time
for(int i = 0; i< songFile.Length; i+=4){

  string artist = songFile[i];
  string title = songFile[i+1];
  double durn = double.Parse(songFile[i+2]);
  Genre gen = (Genre)Enum.Parse(songFile[3]);

  Song s = new Song(artist, title, durn, gen);
    
  library.Add(s);

}
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • I added some more words – Caius Jard Jun 28 '20 at 20:54
  • All the info on enum I saw was showing it nested inside a class it would use. Even here it was suggested as such: https://stackoverflow.com/questions/12386029/separate-class-for-enums so that's why I got stuck with it. Thanks for your corrections! – Alan Shore Jun 28 '20 at 21:11
  • Not sure which answer you're looking at - the accepted answer (see my screenshot here: https://i.stack.imgur.com/lpAti.png) says "dont put enums inside classes" and then shows an example of "don't" (with my annotation- red enum inside blue class) and "do" (with my annotation - red enum outside blue class) – Caius Jard Jun 28 '20 at 21:27
  • Yes, the second option makes more sense to me. I've also added the output I am looking to get to the original post. – Alan Shore Jun 28 '20 at 21:41
  • once you have your SOngs in a lidt you can use LINQ to query for things like `library.Where(song => song.Genre == Genre.Rock)` or `library.Where(song => song.Duration > 300)` etc – Caius Jard Jun 28 '20 at 23:41
  • I've fixed the enum problem and started to address the rest of the errors. It turned out that all I needed is to create a new class but delete the line with "class" and replace it with [Flags] and enum SongGenre { ... } Thanks for your insight! – Alan Shore Jun 29 '20 at 13:53