Is Inferred List Initializes possible? - c#

I know that i can initialize a collection as follows
var array = []{"1", "2", "3"};
which will automatically infer that i want to create an Array of type String, But this will restrict me from Adding or removing indexes from the array since an Array has a fixed size.
Is there anyway to do the same with the Generic List type and the the compiler should infer which type "T" is based on the items in the initializer?
Maybe something like new List(){...}

No, this is not supported - you have to specify the type parameter but can still use collection initializers.
var list = new List<String> { "1", "2", "3" };
You could however create a helper method
public static class ListUtilities
{
public static List<T> New<T>(params T[] items)
{
return new List<T>(items);
}
}
and use it like this.
var list = ListUtilities.New("1", "2", "3");
But this is probably not worth it, you don't gain much if anything at all. And this will create an array first and use it to populate a list. So this is not that different from Keith Nicholas' var list = new[] { "1", "2", "3" }.ToList();.

Here's a pretty nifty example:
static void Main(string[] args)
{
var Customer = new { FirstName = "John", LastName = "Doe" };
var customerList = MakeList(Customer);
customerList.Add(new { FirstName = "Bill", LastName = "Smith" });
}
public static List<T> MakeList<T>(T itemOftype)
{
List<T> newList = new List<T>();
return newList;
}
http://kirillosenkov.blogspot.com/2008/01/how-to-create-generic-list-of-anonymous.html

var list = new[] {"1", "2", "3"}.ToList();

Yes. But no inference .
var li = new List<int> {1,2,3,4,5,6};
Closest you will get is
var li = new List<dynamic> {1,2,3,4,5}

Related

Dictionary with tuples values returning null?

I have a class with a dictionary defined as a private member :
Dictionary<int, (string, string)> arenaIdToSetAndNumber = new Dictionary<int, (string, string)>()
{
{ 70506, ("c16", "337") },
{ 70507, ("c16", "340") },
{ 70508, ("c16", "343") },
{ 70509, ("c16", "346") },
{ 70510, ("c16", "349") },
};
While debugging, I get to an item corresponding to key 70506, I see this with 2 watches:
I try doing var test = arenaIdToSetAndNumber[c.grpId].Item1 and test is set to null just as seen in the second watch! I don't understand why
The debugger and the watcher are not able to infer what is Item1 from the indexer operator [], thus will give you null in the watch. But once you run the code, it will just work fine for reading purpose. For writing purpose instead, you need to take out the whole tuple, edit it and reinsert in the dictionary:
static void Main(string[] args)
{
Dictionary<int, (string, string)> arenaIdToSetAndNumber = new Dictionary<int, (string, string)>()
{
{ 70506, ("c16", "337") },
{ 70507, ("c16", "340") },
{ 70508, ("c16", "343") },
{ 70509, ("c16", "346") },
{ 70510, ("c16", "349") },
};
var myTuple = arenaIdToSetAndNumber[70509];
myTuple.Item1 = "c18";
arenaIdToSetAndNumber[70509] = myTuple;
//System.Console.WriteLine(arenaIdToSetAndNumber[70509].Item1); // This prints c18
}
Otherwise, in one line, just recreate the whole tuple:
arenaIdToSetAndNumber[70509] = ("c18", arenaIdToSetAndNumber[70509].Item2);
All of this because the ValueTuple is a struct. Similar question here
This does not use tuples but solves your problem. Since you want to read the values create an immutable class, use properties to retrive the values.
public class Contents
{
private readonly string leftValue;
private readonly string rightValue;
public Contents(string aLeftValue, string aRightValue)
{
leftValue = aLeftValue;
rightValue = aRightValue;
}
public string LeftValue => leftValue;
public string RightValue => rightValue;
}
Modify your code to use the new class.
Dictionary<int, Contents> arenaIdToSetAndNumber = new Dictionary<int, Contents>()
{
{ 70506, new Contents("c16", "337") },
{ 70507, new Contents("c16", "340") },
{ 70508, new Contents("c16", "343") },
{ 70509, new Contents("c16", "346") },
{ 70510, new Contents("c16", "349") },
};
And you can test it with this.
var content = arenaIdToSetAndNumber[70506];
string leftValue = content.LeftValue;
string rightValue = content.RightValue;
Hope this solves your problem.

LINQ select into array

I am trying to modify a LINQ query to select some properties into an array but am struggling to achieve part of it.
toRun.AddRange(entity.Properties
.Select(property => property.PrimaryField)
.Select(field => new { field, entity = entity.EntityName, table = field.Table, key = entity.EntityIdField })
I need this amending so that if a second property called SecondaryField is not null or empty string it will be added to the results of the first Select statement.
For example if entity.Properties contains:
Property { PrimaryField = "a", SecondaryField = "b" },
Property { PrimaryField = "c", SecondaryField = "" }
I would like the first Select statement to return:
{ "a", "b", "c" }
Appreciate any help thanks.
This seems to reproduce what you want: you have a class with two properties:
public class Foo
{
public string Bar { get; set; }
public string Baz { get; set; }
}
Of which you have a collection:
var foos = new List<Foo>
{
new Foo { Bar = "a", Baz = "b" },
new Foo { Bar = "c", Baz = "" },
};
And from this collection, you want to select all properties that have a non-empty value into an array.
You can do so using SelectMany():
var result = foos.SelectMany(f => new[] { f.Bar, f.Baz })
.Where(p => !string.IsNullOrWhiteSpace(p))
.ToArray();
You select a new array containing the value of both properties, then filter out the values you don't want, and turn the result into an array again.
This should be pretty simple - get both fields, use a Where to remove the null/empties and turn to an array:
var result = entity.Properties.SelectMany(p =>new[]{ p.PrimaryField,p.SecondaryField})
.Where(x => !String.IsNullOrEmpty(x))
.ToArray();
Live example: http://rextester.com/MHM61977

Create default item in a list and return new item

I would like to add a new item at the back of a list, and get the newly created item.
Let's assume that we could do something like this for one moment:
class Temp
{
public string First { get;set;}
public string Second { get;set;}
}
List<string> list = new List<string>();
var newItem = list.Push();
newItem.First="asd";
newItem.Second = "qwe;
this would be easier than
var newItem = new Temp();
newItem.First="asd";
newItem.Second = "qwe;
list.Add(newItem);
especially when I can't use auto-properties.
Is this possible?
Unless you implement your own List type and add the Push method, the only way you can do that is if the T in List can be constructed using a parameterless constructor.
Here's an extension method for that.
This is not recommended, but is an answer to your question.
Something along the lines of this - I did not compile or run this code
public static class ListEx {
public static T Push<T>(this List<T> list) where T: new() {
// Create an instance of T.
var instance = new T();
// Add it to the list.
list.Add(instance);
// Return the new instance.
return instance;
}
}
You can use object initializers:
var list = new List<Temp>();
list.Add(new Temp{ First = "abc", Second = "def" });
Or together with a collection initializer:
var list = new List<Temp> { new Temp{ First = "abc", Second = "def" } };
This turns your four liner into a one liner.
Or with more than one entry:
var list = new List<Temp> {
new Temp{ First = "abc", Second = "def" },
new Temp{ First = "ghi", Second = "jkl" },
new Temp{ First = "mno", Second = "pqr" }
};
And it should of course be a list of Temp instead of a list of string.

C# AddRange List<List<T>>

I need to populate List from List of List objects or List of Enumarable Objects.
Consider the class
public class Data
{
public int ID;
public List<string> Items;
}
List<Data> lstData= new List<Data>();
lstData.Add(new Data { ID = 1, Items = new List<string> { "item1", "item2" } });
lstData.Add(new Data { ID = 2, Items = new List<string> { "item3", "item4" } });
Now , I want to popuplate all the items into one list, like
List<string> values = new List<string>();
values.AddRange(lstData.Select(a => a.Items));
But I am getting error for above AddRange, pls help anyone to write AddRange for this case
Use SelectMany() to flatten a sequence of sequences:
var values = lstData.SelectMany(i => i.Items).ToList()

Concise way to initialise a collection

I can initialise a class in a concise manner using something like:
public static readonly type TYPE_NAME = new type()
{
ClientIp = "ClientIp",
LanguageCode = "LanguageCode",
SessionToken = "SessionToken",
SystemKey = "SystemKey"
};
However is it possible to initialise a collection in a similar way (inherited from List<>)?
List<string> strList = new List<string>{ "foo", "bar" };
List<Person> people = new List<Person>{
new Person { Name = "Pete", Age = 12},
new Person { Name = "Jim", Age = 15}
};
Use a collection initializer
http://msdn.microsoft.com/en-us/library/bb384062.aspx
List<int> list = new List<int> { 1, 2, 3 };
Yes:
var l = new List<int>() { 1, 1, 2, 3, 5 };
You can surely use collection initializer.
To use this,
List<int> collection= List<int>{1,2,3,...};
To use collection initializer it need not to be exactly of List type.
Collection initializer can be used on those types that implements IEnumerable and has one public Add method.
You use Collection initializer feature even in the following type.
public class SomeUnUsefulClass:IEnumerable
{
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
public void Add(int i)
{
//It does not do anything.
}
}
Like,
SomeUnUsefulClass cls=new SomeUnUsefulClass(){1,2,3,4,5};
which is perfectly valid.

Categories

Resources