In C#, is there an inline shortcut to instantiate a List<T> with only one item.
I'm currently doing:
new List<string>( new string[] { "title" } ))
Having this code everywhere reduces readability. I've thought of using a utility method like this:
public static List<T> SingleItemList<T>( T value )
{
return (new List<T>( new T[] { value } ));
}
So I could do:
SingleItemList("title");
Is there a shorter / cleaner way?
Thanks.
Simply use this:
List<string> list = new List<string>() { "single value" };
You can even omit the () braces:
List<string> list = new List<string> { "single value" };
Update: of course this also works for more than one entry:
List<string> list = new List<string> { "value1", "value2", ... };
var list = new List<string>(1) { "hello" };
Very similar to what others have posted, except that it makes sure to only allocate space for the single item initially.
Of course, if you know you'll be adding a bunch of stuff later it may not be a good idea, but still worth mentioning once.
Michael's idea of using extension methods leads to something even simpler:
public static List<T> InList<T>(this T item)
{
return new List<T> { item };
}
So you could do this:
List<string> foo = "Hello".InList();
I'm not sure whether I like it or not, mind you...
A different answer to my earlier one, based on exposure to the Google Java Collections:
public static class Lists
{
public static List<T> Of<T>(T item)
{
return new List<T> { item };
}
}
Then:
List<string> x = Lists.Of("Hello");
I advise checking out the GJC - it's got lots of interesting stuff in. (Personally I'd ignore the "alpha" tag - it's only the open source version which is "alpha" and it's based on a very stable and heavily used internal API.)
new[] { "item" }.ToList();
It's shorter than
new List<string> { "item" };
and you don't have to specify the type.
Use an extension method with method chaining.
public static List<T> WithItems(this List<T> list, params T[] items)
{
list.AddRange(items);
return list;
}
This would let you do this:
List<string> strings = new List<string>().WithItems("Yes");
or
List<string> strings = new List<string>().WithItems("Yes", "No", "Maybe So");
Update
You can now use list initializers:
var strings = new List<string> { "This", "That", "The Other" };
See http://msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx
Yet another way, found on "C#/.Net Little wonders" (unfortunately, the site doesn't exist anymore):
Enumerable.Repeat("value",1).ToList()
For a single item enumerable in java it would be Collections.singleton("string");
In c# this is going to be more efficient than a new List:
public class SingleEnumerator<T> : IEnumerable<T>
{
private readonly T m_Value;
public SingleEnumerator(T value)
{
m_Value = value;
}
public IEnumerator<T> GetEnumerator()
{
yield return m_Value;
}
IEnumerator IEnumerable.GetEnumerator()
{
yield return m_Value;
}
}
but is there a simpler way using the framework?
I've got this little function:
public static class CoreUtil
{
public static IEnumerable<T> ToEnumerable<T>(params T[] items)
{
return items;
}
}
Since it doesn't prescribe a concrete return type this is so generic that I use it all over the place. Your code would look like
CoreUtil.ToEnumerable("title").ToList();
But of course it also allows
CoreUtil.ToEnumerable("title1", "title2", "title3").ToArray();
I often use it in when I have to append/prepend one item to the output of a LINQ statement. For instance to add a blank item to a selection list:
CoreUtil.ToEnumerable("").Concat(context.TrialTypes.Select(t => t.Name))
Saves a few ToList() and Add statements.
(Late answer, but I stumbled upon this oldie and thought this could be helpful)
Try var
var s = new List<string> { "a", "bk", "ca", "d" };
You can also do
new List<string>() { "string here" };
I would just do
var list = new List<string> { "hello" };
Inspired by the other answers (and so I can pick it up whenever I need it!), but with naming/style aligned with F# (which has a standard singleton function per data structure*):
namespace System.Collections.Generic
{
public static class List
{
public static List<T> Singleton<T>(T value) => new List<T>(1) { value };
}
}
* except for ResizeArray itself of course, hence this question :)
In practice I actually name it Create to align with other helpers I define such as Tuple.Create, Lazy.Create[2], LazyTask.Create etc:
namespace System.Collections.Generic
{
public static class List
{
public static List<T> Create<T>(T value) => new List<T>(1) { value };
}
}
[2]
namespace System
{
public static class Lazy
{
public static Lazy<T> Create<T>(Func<T> factory) => new Lazy<T>(factory);
}
}
The declarations make it so easy now to do in C# 10.0 that I don't think theres a need for any helper. Just add the new(){} around any value you want to cast to a list.
List<string> values = new() { "single value" };
If someone landed on this page and trying to add object instead of string, then this worked for me.
new List<myObj> { new myObj{propertName=propstryValue }
, new myObj{propertName=propstryValue }, new myObj{propertName=propstryValue }
};
You need to create an inheritor from the List<> class
public class SingletonList<T> : List<T>
{
public SingletonList(T element) : base(1)
{
this.Add(element);
}
}
and you can use it instead of the base List<> class
var singletonList = new SingletonList<string>("Hello World!");
Related
Came across protobuf-net, awesome! I have a question regarding serialization of empty lists.
I start by declaring the object I want to serialize:
[ProtoContract]
class TestClass
{
[ProtoMember(1)]
List<int> _listOfInts = new List<int>();
public TestClass() { }
public List<int> ListOfInts
{
get { return _listOfInts; }
set { _listOfInts = value; }
}
}
If _listOfInts is empty (but not null) when I deserialse this object is will always be null. This makes sense looking at the protobuf convention and I currently work around this by adding the following method:
[ProtoAfterDeserialization]
private void OnDeserialize()
{
if (_listOfInts == null)
_listOfInts = new List<int>();
}
My question is whether I can achieve this same functionality in a more concise fashion, possibly with an additional attirbute which will initialise null/empty objects as empty instead of null?
There's a fundamental issue here in terms of how protobuf encodes data: the list itself does not appear in the data - just the elements. Because of this, there is simply nowhere obvious to store information about the list. It can be spoofed by sending a Boolean using conditional serialization, but frankly that is a bit hacky and ugly - and adds complexity. Personally, I strongly advise abstracting away from lists that could ever be null. For example:
private readonly List<Foo> items = new List<Foo>();
[ProtoMember(1)]
public List<Foo> Items { get { return items; } }
Or
private List<Foo> items;
[ProtoMember(1)]
public List<Foo> Items { get { return items ?? (items = new List<Foo>()); } }
And note that this advice isn't just about serialization: it is about avoiding arbitrary null-reference-exceptions. People don't usually expect sub-collections to be null.
If you are trying to protect against a null list you could try lazy loading in the property getter.
public List<int> ListOfInts
{
get { return _listOfInts ?? (_listOfInts = new List<int>()); }
set { _listOfInts = value; }
}
This way you can just allow the serializer to return null.
I have need to add to an ICollection<string> property of a class of which I have an IEnumerable of. Here is a complete program which illustrates the problem:
using System;
using System.Collections.Generic;
using System.Linq;
namespace CollectionAddingTest
{
public class OppDocumentServiceResult
{
public OppDocumentServiceResult()
{
this.Reasons = new List<string>();
}
public Document Document { get; set; }
public bool CanBeCompleted
{
get
{
return !Reasons.Any();
}
}
public ICollection<string> Reasons { get; private set; }
}
public class Document
{
public virtual string Name { get; set; }
}
public class Program
{
private static void Main(string[] args)
{
var docnames = new List<string>(new[] {"test", "test2"});
var oppDocResult = docnames
.Select(docName
=> new OppDocumentServiceResult
{
Document = new Document { Name = docName }
});
foreach (var result in oppDocResult)
{
result.Document.Name = "works?";
result.Reasons.Add("does not stick");
result.Reasons.Add("still does not stick");
}
foreach (var result in oppDocResult)
{
// doesn't write "works?"
Console.WriteLine(result.Document.Name);
foreach (var reason in result.Reasons)
{
// doesn't even get here
Console.WriteLine("\t{0}", reason);
}
}
}
}
}
I would expect that each OppDocumentServiceResult would have its referenced Document.Name
property set to works? and each OppDocumentServiceResult should have two reasons added to it. However, neither is happening.
What is special about the Reasons property that I cannot add things to it?
The problem is that oppDocResult is the result of a LINQ query, using deferred execution.
In other words, every time you iterate over it, the query executes and new OppDocumentServiceResult objects are created. If you put diagnostics in the OppDocumentServiceResult constructor, you'll see that.
So the OppDocumentServiceResult objects you're iterating at the end are different ones to the ones you've added the reasons to.
Now if you add a ToList() call, then that materializes the query into a "plain" collection (a List<OppDocumentServiceResult>). Each time you iterate over that list, it will return references to the same objects - so if you add reasons the first time you iterate over them, then you print out the reasons when you iterate over them again, you'll get the results you're looking for.
See this blog post (among many search results for "LINQ deferred execution") for more details.
The issue is your initial Select you are instantiating new OppDocumentServiceResult objects. Add a ToList and you should be good to go:
var oppDocResult = docnames
.Select(docName
=> new OppDocumentServiceResult
{
Document = new Document { Name = docName }
}).ToList();
As Servy pointed out I should have added a bit more detail to my answer, but thankfully the comment he left on Tallmaris' answer takes care of that. In his answer Jon Skeet further expands on the reason, but what it boils down to "is that oppDocResult is the result of a LINQ query, using deferred execution."
Fixed like this, converting to List instead of keeping the IEnumerable:
var oppDocResult = docnames
.Where(docName => !String.IsNullOrEmpty(docName))
.Select(docName
=> new OppDocumentServiceResult
{
Document = docName
}).ToList();
I can only guess (this is a shot in the dark really!) that the reason behind this is that in an IEnumerable the elements are like "proxies" of the real elements? basically the Enumerable defined by the Linq query is like a "promise" to get all the data, so everytime you iterate you get back the original items? That does not explain why a normal property still sticks...
So, the fix is there but the explanation I am afraid is not... not from me at least :(
ForEach() is defined against only List<T> you will not be able to use it to for an ICollection<T>.
You have to options:
((List<string>) Reasons).ForEach(...)
Or
Reasons.ToList().ForEach(...)
Yet, my preferred approach
I would define this extension which can help automating this for you without wasting resources:
public static class ICollectionExtensions
{
public static void ForEach(this ICollection<T> collection, Action<T> action)
{
var list = collection as List<T>;
if(list==null)
collection.ToList().ForEach(action);
else
list.ForEach(action);
}
}
Now I can use ForEach() against ICollection<T>.
Just change your code inside your class
public List<string> Reasons { get; private set; }
I have a client-server application, parts of which "talk" to each other through WCF (netTcp binding).
I have my DataContract, which has 1 field of a 3rd party class:
[Serializable]
public class MyResult{
public ThirdPartyResult Result {get;set;}
/* other fields */
}
Using reflection i see this:
[Serializable]
public class ThirdPartyResult {
private IList result;
public IList Result
{
get { return result ?? (result = new ArrayList());}
}
}
When calling the server from client I have the result as ArrayList on server. After it comes to client the result field becomes a fixed size array.
I didn't use Add service reference, but i use assembly sharing and just do
ChannelFactory<IMyContract>.CreateChannel(new NetTcpBinding("Configuration.Name"), address);
UPDATE: the service contract
[ServiceContract]
[ServiceKnownType(typeof(ArrayList))]
[ServiceKnownType(typeof(ThirdPartyResult))]
public interface IMyContract
{
MyResult GetResult();
}
Now the question:
How can I tell WCF to use ArrayList instead of Array?
I came up with a very bad solution (from my point of view)
Generally I wanted an ArrayList to be preserved to be able to add items to it. Finally I came up with the solution below. Yes, I know, this is completely bad, and that's why I'm still looking for some better variant.
if (thirdParty.Results != null && thirdParty.Results.IsFixedSize)
{
var results = new ArrayList(thirdParty.Results);
// Finding result by ReferenceEquals to not be tight to private variable name
var resultsField = thirdParty.GetType()
.GetFields(BindingFlags.Default | BindingFlags.Instance | BindingFlags.NonPublic)
.Where(f => ReferenceEquals(f.GetValue(thirdParty), thirdParty.Results))
.FirstOrDefault();
if (resultsField != null)
resultsField.SetValue(thirdParty, results);
}
thirdParty.AddResult(otherChild);
When you create a new Service Reference (or configuring an existing reference) in the Visual Studio there is a property something like "Deserialize arrays as" and there you can choose array/list/etc. You could take a look at the generated code and change your code to achieve what you want.
Please see the following:
WCF: Serializing and Deserializing generic collections
This solved my problem: Both the private member and custom property method work for me.
[DataMember]
private List<Person> members = new List<Person>();
OR change the property to:
[DataMember]
private Iist<Person> members = new Iist<Person>();
[DataMember()]
public IList<Person> Feedback {
get { return m_Feedback; }
set {
if ((value != null)) {
m_Feedback = new List<Person>(value);
} else {
m_Feedback = new List<Person>();
}
}
}
Ultimately your contract contains no information that would make it choose any particular implementation. The best way to fix this would be; to make result well-typed, perhaps as ArrayList:
private ArrayList result;
public IList Result {
get { return result ?? (result = new ArrayList());}
}
personally I'd hope to see a List<T> with [DataContract]/[DataMember] etc, but...
if nothing else then I would write an extension class to extend ThirdPartyResult
public static class ThirdPartyResultExtension
{
public static ArrayList ResultsAsArrayList(this ThirdPartyResult d)
{
ArrayList list = new ArrayList();
list.AddRange(d.Result);
return list;
}
}
public class ThirdPartyResult
{
private IList result;
public IList Result
{
get { return result ?? (result = new ArrayList()); }
}
}
and use it like
ThirdPartyResult r;
ArrayList arrlist = r.ResultsAsArrayList();
I have the following enum:
public enum SymbolWejsciowy
{
K1 , K2 , K3 , K4 , K5 , K6 , K7 , K8
}
I want to create a list using the values of this enum:
public List<SymbolWejsciowy> symbol;
I have tried a couple different ways to add the enum values to the list:
SymbolWejsciowy symbol;
symbol.Add(symbol = SymbolWejsciowy.K1);
and
symbol.Add(SymbolWejsciowy.K1);
However, I always get the following exception:
Object reference not set to an instance of an object.
How can I correctly accomplish this?
As other answers have already pointed out, the problem is that you have declared a list, but you haven't constructed one so you get a NullReferenceException when you try to add elements.
Note that if you want to construct a new list you can use the more concise collection initializer syntax:
List<SymbolWejsciowy> symbols = new List<SymbolWejsciowy>
{
SymbolWejsciowy.K1,
SymbolWejsciowy.K2,
// ...
};
If you want a list containing all the values then you can get that by calling Enum.GetValues:
List<SymbolWejsciowy> symbols = Enum.GetValues(typeof(SymbolWejsciowy))
.Cast<SymbolWejsciowy>()
.ToList();
In your option 1 SymbolWejsciowy instance and your list have the same name, I imagine that's a typo error.
Without taking that into account I'd say you didn't created the instance of the list
symbol = new List<SymbolWejsciowy>();
Your code never initializes the list. Try this:
public List<SymbolWejsciowy> symbol = new List<SymbolWejsciowy>();
symbol.Add(SymbolWejsciowy.K1);
and
SymbolWejsciowy mySymbol= SymbolWejsciowy.K2;
symbol.Add(mySymbol);
It sure would be nice if Enum.GetValues() had been updated for generics way back in C# 2.0. Well, guess we have to write it ourselves:
static class EnumHelpers<T> where T : struct
{
public class NotAnEnumException : Exception
{
public NotAnEnumException() : base(string.Format(#"Type ""{0}"" is not an Enum type.", typeof(T))) { }
}
static EnumHelpers()
{
if (typeof(T).BaseType != typeof(Enum)) throw new NotAnEnumException();
}
public static IEnumerable<T> GetValues()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
public static T Parse(string value)
{
return (T)Enum.Parse(typeof(T), value);
}
}
I included Parse() because it benefits from generics in the same way.
Usage:
var symbols = EnumHelpers<SymbolWejsciowy>.GetValues().ToList();
SymbolWejsciowy s = EnumHelpers<SymbolWejsciowy>.Parse("S2");
(ASIDE: I also wish you could write where T : enum for just this sort of thing. Also, where T : delegate.)
None of these answers worked for me.
I think most people just want a List<string> or list of values after combining many enums together. This should help:
static class MyPets {
enum Cats
{
Felix,
Hairy,
TunaBreath
}
enum Dogs
{
Fido,
Fred,
Butch
}
public static void PrintPets() {
List<string> Pets = new List<string>();
Pets.AddRange(Enum.GetNames(typeof(Cats)).ToList());
Pets.AddRange(Enum.GetNames(typeof(Dogs)).ToList());
foreach(string p in Pets){
Console.WriteLine(p);
}
}
}
// RESULT
Felix
Hairy
TunaBreath
Fido
Fred
Butch
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...
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.
You need to implement the ToString method.
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 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);
}
}