views:

2699

answers:

5

Normally, I'd choose List<String> [or, in VB, List(Of String)] over StringCollection whenever possible: see also Best string container.

However, as it seems, generics — and hence, List<String> — are apparently not supported in VS 2008's settings designer. Therefore, if I want to use a list of strings in my user settings, I have to resort to using a StringCollection there.

Now as I don't want to see StringCollection throughout my code, I need to convert it to List<String>. How do I do this efficiently? Or, even better, am I mistaken and there is a way to use List<String> in settings designer?

EDIT: I have to use .NET 2.0.

+6  A: 

Converting StringCollection to List<string> is wonderfully simple if you're using .NET 3.5.

var list = stringCollection.Cast<string>().ToList();

Regarding your second question, I do seem to recollect that it is possible to use List<string> in the settings designer of Visual Studio. If you select custom type then browser to the appropiate type, it should work. However, I could be mistaken on that, so I'll need to verify it.

Noldorin
If performance is a concern, I'd choose Cast instead of OfType, just to avoid the type test that OfType is performing. We know all instances are of type string. Anyway, this may be negligible.
Jerome Laban
@Jerome: Yeah, you're probably right about that, though indeed it should be negligible in most situations. Calling OfType rather than Cast is only really needed when you're dealing with collections of mixed types anyway. (Not sure if you realised I'd just updated the answer shortly before your comment anyway, for exactly this reason.)
Noldorin
A: 

If you're using C# 3.0 and .NET 3.5, you can create a list using

var list = new List<string>(new StringCollection().Cast<string>());

The other way around is :

var c = new StringCollection();
c.AddRange(new List<string>().ToArray());
Jerome Laban
+1  A: 

Why not keep it simple and just iterate though it and add the items to the list, or have i misunderstood something?

public static List<string> Convert(StringCollection collection)
{
    List<string> list = new List<string>();
    foreach (string item in collection)
    {
        list.Add(item);
    }
    return list;
}
Patrik
+4  A: 

If you have to use .NET 2.0, I would imagine the cleanliest option would be to create a wrapper for StringCollection that implements IEnumerable<string> and IEnumerator<string> for StringCollection and StringEnumerator respectively. (note: according to metadata, StringEnumerator does not implement IEnumerator). Sample below. However, at the end of the day, someone, somewhere is going to be doing a foreach() over the StringCollection, so one could argue that a simple foreach(string item in stringCollection) and adding to the List<string> would suffice; I doubt this wouldn't be performat enough for your needs.

You could also implement IList<string> using this approach as well, to save you duplicating the underlying strings, but you'll pay a penalty of having the "wrapper" type delegate calls (one more method call on the stack!). I would suggest you treat things in-terms of interfaces within your system anyway IEnumberable<string>, IList<string> etc, instead of the concrete List, it will guide you down a path to greater flexibility.

    static void Main(string[] args)
    {
        StringCollection stringCollection = new StringCollection();
        stringCollection.AddRange(new string[] { "hello", "world" });

        // Wrap!
        List<string> listOfStrings = new List<string>(new StringCollectionEnumerable(stringCollection));

        Debug.Assert(listOfStrings.Count == stringCollection.Count);
        Debug.Assert(listOfStrings[0] == stringCollection[0]); 

    }

    private class StringCollectionEnumerable : IEnumerable<string>
    {
        private StringCollection underlyingCollection; 

        public StringCollectionEnumerable(StringCollection underlyingCollection)
        {
            this.underlyingCollection = underlyingCollection; 
        }

        public IEnumerator<string> GetEnumerator()
        {
            return new StringEnumeratorWrapper(underlyingCollection.GetEnumerator()); 
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator(); 
        }
    }

    private class StringEnumeratorWrapper : IEnumerator<string>
    {
        private StringEnumerator underlyingEnumerator; 

        public StringEnumeratorWrapper(StringEnumerator underlyingEnumerator)
        {
            this.underlyingEnumerator = underlyingEnumerator;
        }

        public string Current
        {
            get
            {
                return this.underlyingEnumerator.Current; 
            }
        }

        public void Dispose()
        {
            // No-op 
        }

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return this.underlyingEnumerator.Current;
            }
        }

        public bool MoveNext()
        {
            return this.underlyingEnumerator.MoveNext(); 
        }

        public void Reset()
        {
            this.underlyingEnumerator.Reset(); 
        }
    }
Phil Price
A: 

stringCollection.Cast().ToList()

Taz