简体   繁体   中英

C#: Class return value - or is there a better way?

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.

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...

几个简单的选择将是重写类的ToString()方法(以便在此上下文中使用它时,它返回以逗号分隔的项目列表),或者您可以提供一个使列表变平的属性。

您需要实现ToString方法。

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);

    }
}

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"

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM