tags:

views:

932

answers:

8

Hello,

I currently have a class that uses the KeyValuePair with List to store a collection of tracks in the format of Key = track, Value = artist.

I'm trying to provide a way of searching for a particular track and if there are any matches then return the entire matching CD.

This is my attempt so far:

public CompilationCD FindTrackInComCD(string track)
{
    CompilationCD temp = new CompilationCD();

    List<CD> tempComCols = _cdCollection.FindAll(delegate(CD cd)
    { return cd.GetType() == temp.GetType(); });

    foreach (KeyValuePair<string, string> comCD in tempComCols)
    {
        if (comCD.Key.Contains(track))
        {
            return comCD;
        }
    }

    throw new ArgumentException("No matches found");
}

I have a collection of Cd's of type CD (List<CD>) therefore I create a new List<> of the appropiate type by comparing it to the temp List.

When compiling I get the following errors:

Cannot convert type 'CDCollection.CD' to System.Collections.Generic.KeyValuePair<string,string>'

Cannot implicitly convert type 'System.Collections.Generic.KeyValuePair<string,string>'

(CDCollection is my project namespace and CD/CompilationCD are the classes)

Sorry for this seeming like a similar question to one I've previously asked. I tried to use the methods I was given before but I'm a bit stumped; I've not used List<> or KeyValuePair very often.

This is the CD Class:

using System;

using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text;

namespace CDCollection { public class CD { #region Fields private readonly string _artist; private readonly string _album; private List _track = new List(); #endregion

    #region Constructors
    public CD()
    {
        _artist = "";
        _album = "";
        _track = null;
    }

    public CD(string albumName)
    {
        _album = albumName;
    }

    public CD(string artistName, string albumName)
    {
        _artist = artistName;
        _album = albumName;
    }

    #endregion

    #region Properties
    /// <summary>
    /// Get/Set Artist Name
    /// </summary>
    public virtual string Artist
    {
        get
        {
            return _artist;
        }
        set
        {
            value = _artist;
        }
    }

    /// <summary>
    /// Get/Set Album
    /// </summary>
    public string Album
    {
        get
        {
            return _album;
        }
        set
        {
            value = _album;
        }
    }

    /// <summary>
    /// Get/Set Track Name
    /// </summary>
    public virtual List<string> Track
    {
        get
        {
            return _track;
        }
        set
        {
            value = _track;
        }
    }

    #endregion

    #region ToString()
    /// <summary>
    /// Custom ToString() Method
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        //Create new StringBuilder object
        StringBuilder sb = new StringBuilder();

        sb.Append("Artist Name");

        //Display error if Artist is not available
        if (_artist == null || _artist == "")
        {
            sb.Append("\nNo Artist Entered");
        }
        else
        {
            sb.Append("\n" + this._artist);
        }

        sb.Append("\n");
        sb.Append("\nAlbum Name");

        //Display error if Album is not available
        if (_album == null || _album == "")
        {
            sb.Append("\nNo Album Entered");
        }
        else
        {
            sb.Append("\n" + this._album);
        }

        sb.Append("\n");
        sb.Append("\nTrack Name");
        sb.Append("\n");

        //Iterate through all tracks stored in list
        foreach (string trackName in _track)
        {
            //Print each artist
            sb.Append("\n" + trackName);
        }

        sb.Append("\nEnd of CD Record.........");

        return sb.ToString();
    }

    #endregion
}

}

This is the CompilationCD class:

using System;

using System.Collections.Generic; using System.Linq; using System.Text;

namespace CDCollection { public class CompilationCD : CD { #region Fields

    private readonly string _artist;
    private readonly string _album;
    private List<KeyValuePair<string,string>> _tracks = new List<KeyValuePair<string,string>>();

    //List<KeyValuePair> Reference.
    //http://msdn.microsoft.com/en-us/library/6sh2ey19(VS.85).aspx

    #endregion

    #region Constructors

    public CompilationCD()
    {
        _album = "";
        _artist = "Various Artists";
    }

    public CompilationCD(string albumName):base(albumName)
    {
        _album = albumName;
        _artist = "Various Artists";
    }

    #endregion

    public void AddTracks(string track, string artist)
    {
        _tracks.Add(new KeyValuePair<string, string>(track, artist));
    }

    #region Properties

    public override string Artist
    {
        get
        {
            return this._artist;
        }
    }

    public new List<KeyValuePair<string,string>> Track
    {
        get
        {
            return _tracks;
        }
        set
        {
            _tracks = value;
        }
    }


    #endregion

    #region ToString()

    //TEST
    public override string ToString()
    {
        //Create new StringBuilder object
        StringBuilder sb = new StringBuilder();

        sb.Append("Artist Name");

        //Display error if Artist is not available
        if (_artist == null || _artist == "")
        {
            sb.Append("\nNo Artist Entered");
        }
        else
        {
            sb.Append("\n" + this._artist);
        }

        sb.Append("\n");
        sb.Append("\nAlbum Name");

        //Display error if Album is not available
        if (base.Album == null || base.Album == "")
        {
            sb.Append("\nNo Album Entered");
        }
        else
        {
            sb.Append("\n" + base.Album);
        }

        sb.Append("\n");
        sb.Append("\nTrack Name");
        sb.Append("\n");

        ////Iterate through all tracks stored in list
        //foreach (string trackName in base.Track)
        //{
        //    //Print each artist
        //    sb.Append("\n" + trackName);
        //}

        for(int i = 0; i <= _tracks.Count; i++)
        {
            string track = _tracks[i].Key;
            string artist = _tracks[i].Value;

            sb.Append("\nTrack");
            sb.Append(track);
            sb.Append("\nArtist");
            sb.Append(artist);
        }

        sb.Append("\nEnd of Compilation CD Record.........");

        return sb.ToString();
    }

    #endregion
}

}

I have strict rules that mean i have to inherit from CD to create my CompilationCD as well as using a List> for my track collection, it needs to hold both a track and artist. Crazy i know =/

Furthermore i must store ALL types of cd in a list of type CD ( List ).

+3  A: 

Why not use a dictionary? They are a list of key value pairs, but provide easy access via the key.

McKay
Of course, i can't believe i didn't think of that.Thanks!
Jamie Keeling
After trying to implement the dictionary it turns out there's a chance of it breaking too much.
Jamie Keeling
What do you mean, "breaking"? Care to elaborate?
McKay
My program was designed in pairs, my partner has done their own contribution but didn't leave much to be changed without the majority of the entire application being changed.
Jamie Keeling
Well, I think a dictionary is your best bet. You might as well do the refactoring to clean things up.
McKay
Okay, how would i access the Key and Value through the properties if i store the dictionary in a List<> ?
Jamie Keeling
A: 

that's because tempComCols will return CD and not KeyValuePair<string, string>

Ciwee
A: 

Your List doesn't contain KeyValuePairs, so you can't loop through it as if it did. Try something like this:

foreach (CD comCD in tempComCols)
{
    if (comCD.MyKeyValueProp.Key.Contains(track))
    {
        return comCD;
    }
}

But as McKay said, if your CD class does nothing but encapsulate a KeyValuePair, a Dictionary would be much easier.

Michael Myers
+1  A: 

The problem is in your foreach loop. tempComCols is a List<CD>, but comCD is a KeyValuePair<string, string>. So, your loop results in an invalid type conversion.

Unfortunately, since we don't know what the CD class (interface?) looks like, I can't suggest a fix in terms of its properties.

EDIT: The following is perhaps a better version of your method (though, I haven't debugged it correctly):

public CompilationCD FindTrackInComCD(string track)
{
    CompilationCD temp = new CompilationCD();

    temp = _cdCollection.Where(cd => cd is CompilationCD)
                        .Cast<CompilationCD>()
                        .Where(com_cd => com_cd.Tracks.ContainsKey(track))
                        .FirstOrDefault();

    if (temp != null)
        return temp;
    else throw new ArgumentException("No matches found");
}

You can't cast a CompilationCD to a KeyValuePair<string, string>, so we just use the CompilationCD class directly. We can pass off the responsibility for searching the track list to the IEnumerable<T> extenion methods provided by System.Linq, which makes this method very easy.

Dathan
I've added the classes for the CD and CompilationCD =]
Jamie Keeling
Which version of the .Net framework are you using? There are differences in the "standard" idiom based on whether LINQ is available or not.
Dathan
I'm using .Net 3.5
Jamie Keeling
A: 

tempComCols is list of CD items: List<CD> tempComCols ... and you want to iterate over something that is of type IEnumerable: foreach (KeyValuePair<string, string> comCD in tempComCols)

bitbonk
A: 

You are enumerating a List<CD> and assigning to a KeyValuePair<string, string>.

You can rewrite your method using LINQ in C# 3 like this:

public CompilationCD FindTrackInComCD(string track) {
    return _cdCollection.OfType<CompilationCD>().FirstOrDefault(cd => cd.Name.Contains(track, StringComparison.CurrentCultureIgnoreCase));
}

By the way, you can get the System.Type object for CompilationCD by writing typeof(CompilationCD); you don't need to call GetType().

SLaks
A: 
  1. you can use: {cd is CompilationCD}; instead of { return cd.GetType() == temp.GetType(); });

  2. if I understand correctly and CD is some sort of Dictionary, you can rewrite the function as:

    public CompilationCD FindTrackInComCD(string track) { return (CompilationCD)_cdCollection.Find(delegate(CD cd) { return (cd is CompilationCD) && (cd.Contains(track))}); }

dtroy
A: 

Use KeyedCollection http://msdn.microsoft.com/en-us/library/ms132438.aspx

Rohit