Reputation: 3969
I created a class that had one member of type List. I could then add to this using ClassNameInstance.Add()
.
We are now using some code from a third-party that will automatically use any class I create and its values. Except lists. It only returns the first element in the list.
What I need is a comma-separated version returned instead for this third-parties code to use. Now I could just append the Strings to a String member, but this doesn't look as nice as the .Add() method.
So I wanted to create my own Class that I could have an Add() method for but could access its single value like so:
MyClass1.Add("Test1");
MyClass1.Add("Test2");
Console.WriteLine(MyClass2);
The output I would like would be Test1, Test2
. I hope this makes sense!
UPDATE1:
Seems the above may not have been clear.
public class MyClass1
{
????
}
public class MyClass2
{
MyClass1 mc1 { get; set; }
String name { get; set; }
}
The third party code will use MyClass2 and its assigned values. When I used List instead of MyClass1 I only get the first value in the list, but need a CSV list as a String returned.
MyClass2 mc2 = new MyClass2();
mc2.mc1.Add("Test1");
mc2.mc1.Add("Test2");
Console.WriteLine(mc2.mc1) should output -> Test1, Test2
Hope that clears things up some more!
Thanks everyone! :)
UPDATE2:
It seems everyone is suggesting the same thing - use ToString().
Unfortunately, the third-party code will look at my class and determines the members type and value automatically. This means that I am not able to pass the code the value that would be returned by calling ToString().
I kind of need the add/remove functionality of a List<> but when used its value returns as a single CSV string.
Upvotes: 0
Views: 9462
Reputation: 5428
The simplest solution is probably to inherit from the StringCollection class and just override ToString. Otherwise this class already has everything you are asking about.
public class MyClass : System.Collections.Specialized.StringCollection
{
public override string ToString()
{
var c = new string[this.Count];
this.CopyTo(c,0);
return string.Join(",", c);
}
}
Then you can use it just like you were trying to before. No need to get fancy with generics for this simple usage.
Edit:
Classes themselves don't have a return value, so the 3rd party code must be reading properties. You should be able to override ToString() as described above then expose a property that returns the ToString(). That would probably make the string value visible to the 3rd party code
public class MyClass : System.Collections.Specialized.StringCollection
{
public string MyValue
{
get { return this.ToString(); }
}
public override string ToString()
{
var c = new string[this.Count];
this.CopyTo(c,0);
return string.Join(",", c);
}
}
Upvotes: 0
Reputation: 3969
Not really the answer I wanted, but it seems that I couldn't do what I wanted.
In the class where I wanted to have my second class as a member, I made that member a String so the third-party code would work as I wanted.
I created a second class that had a List<String>
as a public member and then a Method called .ToCSV()
to output the list as a csv string. I added a .Add()
method to add the strings to the list to save having to go Class1.Class2.Add()
.
Then just before the third-party code would use my class, I do:
MyClass1.MyString = MyClass2.ToCSV();
Thus giving me basically what I wanted in a round about way!!
Thanks for everyone's input and help!
Neil
Upvotes: 0
Reputation: 11449
Here's an extension I wrote to join the items in an IEnumerable<T>
public static string Join<T>(this IEnumerable<T> collection, string separator, Func<T, object> selector) { if (null == separator) throw new ArgumentException("separator"); if (null == selector) throw new ArgumentException("selector"); Func func = item => { var @object = selector(item); return (null != @object) ? @object.ToString() : string.Empty; }; return string.Join(separator, collection.Select(func).ToArray()); }
It can be used like this:
List<Person> list = new List<Person>() { new Person() { FirstName = "Magic", LastName = "Johnson" }, new Person() { FirstName = "Michael", LastName = "Jordon" }, new Person() { FirstName = "Larry", LastName = "Bird" } }; var value = list.Join(", ", p => p.FirstName); // value is "Magic, Michael, Larry"
Upvotes: 0
Reputation: 37164
A couple of easy options would be to override the ToString() method of your class (so that when it is used in this context it returns a comma-delimited list of items) or you can provide a property that flattens the list.
Upvotes: 1
Reputation: 1500135
I'm not sure that you need an extra class here:
List<string> list = new List<string>();
list.Add("Test1");
list.Add("Test2");
Console.WriteLine(string.Join(", ", list.ToArray());
You could wrap this behaviour in a class just to get it automatically invoked on ToString
:
public sealed class StringJoiningList
{
private readonly List<string> list = new List<string>();
public void Add(string item)
{
list.Add(item);
}
public override string ToString()
{
return string.Join(", ", list.ToArray());
}
}
Now that's assuming you just want a List<string>
- it also doesn't let you access the items other than by the ToString()
method. All of that is fixable of course, if you could give more information. You could even just derive from List<T>
:
public class StringJoiningList<T> : List<T>
{
public override string ToString()
{
return string.Join(", ", this.Select(x => x.ToString()).ToArray());
}
}
I'm not entirely sure I like the idea, but it depends on what you need to do...
Upvotes: 8