C# Equivalent to Java's Double Brace Initialization? - c#

Expected code in C# (that Java has)
List<String> myList = new List<String>() {{
add("Hello");
add("World!");
}}
// myList = [ "Hello", "World" ]
Just wondering if there is an equivalent, possibly with C#'s static constructors?
EDIT:
To clarify this isn't explicitly for Collections but for any class structure.
For example:
abstract class myClass {
String data;
List<String> list;
void setupList() {
list = new List<String>();
}
}
...
var obj = new myClass() {{
data = "Yo";
setupList();
}};

You're looking for the collection initializer syntax:
List<String> myList = new List<String>() {"Hello","World!"};

This is an object initializer that also uses collection initializers (note the type inference in the collection initializers, the List that is created is of type List) :
var myClass = new MyClass{
Data = "foo",
List = new List{"item1", "item2"},
IntArray = new[]{1,2,3},
Dictionary = new Dictionary<string,string>{{"key1","value1"},{"key2","value2"}},
};
You can't call arbitrary methods like SetupList() in an initializer, instead you would initialize the List property the first time it is accessed or statically, etc.
You can use the Lazy class or implement it yourself like so (?? is the null coalescing operator):
class MyClass{
public string Data { get; set; }
private IList<string> _list0 = new List();
public IList<string> List0
{
get
{
return _list0;
}
}
private IList<string> _list1;
public IList<string> List1
{
get
{
return _list1 ?? (_list1 = new List());
}
}
private readonly Lazy<IList<string>> _lazyList = new Lazy<IList<string>>(() => new List<string>());
public IList<string> List2
{
get
{
return _lazyList.Value;
}
}
}

This is how you can add items to a list of strings
List<string> myList = new List<string>();
myList.Add("Hello");
myList.Add("World!");
And if you want to remove them you can simply do this
myList.Remove("Hello");
myList.Remove("World!");

Related

Generic method for dictionary Object with variable values and loop through it

I need to convert all my dictionary objects that coming from an api which are stored in results(model) to StudentList type.
I am doing it for one property as shown below:
StudentList<StudentData> testList = new StudentList<StudentData>();
foreach(KeyValuePair<string, IEnumerable<StudentData>> pair in result.StudentDataDetails)
{
foreach(var x in pair.Value)
testList.Add(x);
}
Like StudentData , there are other class objects like TeacherData, ParentData.. all these need to changed to StudentList<TeacherData>, StudentList<ParentData>.
I am trying to build a generic method for this..any help would be appreciated. I need to check if there is a dictionary property from results in the following way Dictionary<string, IEnumerable<T>> then change the dictionary as mentioned above. T is StudentData, TeacherData and so on. The generic method needs to return the StudentList<T>.
Thank you
You can write a generic method that takes in a dictionary of type <string, IEnumerable<T>> and returns a List<T> from all the values. This will work for any type T, whether it's a Student, Teacher, Parent, etc:
public static List<T> GetAllValues<T>(Dictionary<string, IEnumerable<T>> input)
{
return input?.SelectMany(kvp => kvp.Value).ToList();
}
Sample usage:
var studentDict = new Dictionary<string, IEnumerable<Student>>
{
{"1", new List<Student> {new Student {Name = "First"}}},
{"2", new List<Student> {new Student {Name = "Second"}}},
{
"3", new List<Student>
{
new Student {Name = "Third"},
new Student {Name = "Fourth"}
}
},
};
var studentList = GetAllValues(studentDict);
studentList.ForEach(s => Console.WriteLine(s.Name));
Output
I dont know how works your classe StudentList, but, i built a sample that could help you.
public class StudentReaderAPI
{
public StudentList<T> BuildList<T>(Dictionary<string, IEnumerable<T>> dataDetails) where T : AbstractDataDetails
{
if (dataDetails == null) return null;
return new StudentList<T>(dataDetails.Values.SelectMany(x => x));
}
}
public class StudentList<T> : List<T> where T : AbstractDataDetails
{
public StudentList(IEnumerable<T> enumerable) : base(enumerable)
{
}
//Your List logic here
}
public abstract class AbstractDataDetails
{
//Common properties of DataDetails
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class StudentData : AbstractDataDetails
{
//StudentData Properties here
}
public class ParentData : AbstractDataDetails
{
//ParentData Properties here
}
public class TeacherData : AbstractDataDetails
{
//TeacherData Properties here
}
You can create the generic method which take the dictionary as input
public StudentList<T> GenericMethod(Dictionary<string, T> dictionary)
{
StudentList<T> testList = new StudentList<T>();
foreach(KeyValuePair<string, IEnumerable<T>> pair in dictionary)
{
foreach(var x in pair.Value)
testList.Add(x);
}
return testList;
}
Then call this method and pass the dictionary
GenericMethod(result.StudentDataDetails);
GenericMethod(result.TeacherDataDetails);

List of dynamic objects with dynamic groupBy

I need to achieve something like this but I cannot figure how to make it work:
class Program
{
static List<dynamic> myList = new List<dynamic>();
static void Main(string[] args)
{
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test1", Test2 = "test2" });
// I need to pass a dynamic list of expression like:
GenerateGroup<dynamic>(x=>x.Test, x => x.Test2); //groups myList in 2 groups
GenerateGroup<dynamic>(x=>x.Test2); //groups myList in a single group
}
private static void GenerateGroup<T>(params Expression<Func<T, object>>[] properties)
{
//I need to group for the properties passed as parameters
var result= myList.GroupBy(properties);
}
}
I receive compiler errors:
An expression tree may not contain a dynamic operation
This is only an example of a complex application but at the end, I need to use a list of dynamics and I need to group them with a dynamic list of properties. This is because I read data/properties from multiple PDF sources and it's not possible to use static classes.
Is it possible to fix this error or it is a compiler limitation and I need to approach the problem in another way?
UPDATE
I think I've made a step forward thanks to your answers:
class Program
{
static List<dynamic> myList = new List<dynamic>();
static List<Foo> myListFoo = new List<Foo>();
static void Main(string[] args)
{
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test1", Test2 = "test2" });
myListFoo.Add(new Foo { MyProperty =1});
GenerateGroup<dynamic>(x =>new { x.Test, x.Test2});
GenerateGroup<Foo>(x=>x.MyProperty);
}
private static void GenerateGroup<T>(Func<T, object> properties)
{
var result= myList.GroupBy(properties);
result = myListFoo.GroupBy(properties);
}
}
public class Foo
{
public int MyProperty { get; set; }
}
and I have only a compilation error on groupBy:
'List<dynamic>' does not contain a definition for 'GroupBy' and the best extension method overload 'ParallelEnumerable.GroupBy<T, object>(ParallelQuery<T>, Func<T, object>)' requires a receiver of type 'ParallelQuery<T>'
You need to make some changes to your code:
Expression<Func<,>> is not what you are looking for, the Where overloads accepted by IEnumerable<T> all use Func<,>
There's no reason to make GenerateGroup generic if you are going to hard-code dynamic
Instead of passing multiple parameters, you should create an object that includes the data you want to group by
If you mix all those points, you should end up with something like this:
static void Main(string[] args)
{
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test1", Test2 = "test2" });
// I need to pass a dynamic list of expression like:
GenerateGroup(x => new { x.Test, x.Test2 } ); //groups myList by Test and Test2
GenerateGroup(x => x.Test2); //groups myList in a single group
}
private static void GenerateGroup(Func<dynamic, object> groupper)
{
var groupped = myList.GroupBy(groupper);
}

LINQ creating a new anonymous type when selecting a property that is a dictionary

I have a Simple POCO like this:
[JsonObject(NamingStrategyType = typeof (CamelCaseNamingStrategy))]
public class MyType
{
public string Id { get; set; }
public string Name;
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> TypeDetails { get; set; }
}
and a method that gives me a list of MyType
i'm trying to return a list of Dictionary<string,object> with all the TypeDetails of the object list i got.
like this:
types.Select((myType) => myType.TypeDetails)
however, when i run this, what i get is a list of Dictionaries, but with the following shape:
[
{TypeDetails: {the dictionary i want},
{TypeDetails: {the dictionary i want}},
(...)
]
what i was expecting:
[
{the dictionary i want},
{the dictionary i want},
(...)
]
to clarify: i'd like this to be true:
types[0].TypeDetails.equals(r[0])
It's the same as if i were doing
types.Select((myType) => new {myType.TypeDetails})
if i get any other property the select behaves as i expected it.
i can't find any doc that indicates whether dictionaries get a special treatment, nor any other clue about why this is happening.
Use .SelectMany() on the Dictionary's values, like so:
types.SelectMany((myType) => myType.TypeDetails.Values)
Either your return expectation/description is out:
i'm trying to return a list of Dictionary<string,Object>
or, (assuming (myType) is of type MyType), your real code does not match:
types.Select((myType) => myType.TypeDetails)
The example code below does return a collection of Dictionary<string,Object>, it'd be interesting to see where your code differs from it:
var data = new[]
{
new MyType()
{
TypeDetails = new Dictionary<string, object>() { { "foo", "bar" } }
},
new MyType()
{
TypeDetails = new Dictionary<string, object>() { { "baz", "qux" } }
},
};
var r = data.Select(d => d.TypeDetails);

How to get the name of the list

I create a list first
List<String> dummy1 = new List<String>();
List<String> dummy2 = new List<String>();
List<String> dummy3 = new List<String>();
List<String> dummy4 = new List<String>();
Before I add the list to Dictionary
Dictionary<int, List<String>> _d = new Dictionary<int, List<String>>()
{
{1, dummy1},
{2, dummy2},
{3, dummy3},
{4, dummy4},
};
then I want to have the name of the list by looping the key
foreach (var key in _d.Keys)
{
MessageBox.Show(_d[key].GetType().Name);
}
but the output is list 1, I want to get the
dummy1
dummy2
dummy3
dummy4
As I commented, you can only do this with really funky syntax. Here's an example of what I mean
void Main()
{
List<String> dummy1 = new List<String>();
List<String> dummy2 = new List<String>();
List<String> dummy3 = new List<String>();
List<String> dummy4 = new List<String>();
var _d = new Dictionary<int, Expression<Func<List<String>>>>()
{
{1, () => dummy1},
{2, () => dummy2},
{3, () => dummy3},
{4, () => dummy4},
};
foreach(var kvp in _d)
{
MessageBox.Show(kvp.Value.nameof());
}
}
// Define other methods and classes here
public static class TestExtension
{
public static String nameof<T>(this Expression<Func<T>> accessor)
{
return nameof(accessor.Body);
}
public static String nameof<T, TT>(this T obj, Expression<Func<T, TT>> propertyAccessor)
{
return nameof(propertyAccessor.Body);
}
private static String nameof(Expression expression)
{
if (expression.NodeType == ExpressionType.MemberAccess)
{
var memberExpression = expression as MemberExpression;
if (memberExpression == null)
return null;
return memberExpression.Member.Name;
}
return null;
}
}
The main issue is that you need the dictionary to store an expression, rather than a List
Secondly, to actually ACCESS the list, you need to do this:
var list = _d[1].Compile()();
And lastly, if dummy1 ever gets reassigned, you'll lose the reference to the list you're expecting.
In short, it's very unlikely that you need to do this. It's rare that the variable names in code should actually affect behaviour.
You are assigning data to a variable name and you are going to get the variable name in order to access the data. I would create a simple object with a Name and List and add it to the Dictionary.
Just make a custom class that inherits from List<string> and have a Name property.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
MyList dummy1 = new MyList("dummy1");
MyList dummy2 = new MyList("dummy2");
MyList dummy3 = new MyList("dummy3");
MyList dummy4 = new MyList("dummy4");
Dictionary<int, MyList> _d = new Dictionary<int, MyList>()
{
{1, dummy1},
{2, dummy2},
{3, dummy3},
{4, dummy4},
};
foreach (var key in _d.Keys)
{
Console.WriteLine(_d[key].Name);
}
}
}
public class MyList : List<String>
{
private string name;
public string Name
{
get
{
return name;
}
}
public MyList(string name)
{
this.name = name;
}
}
Results:
dummy1
dummy2
dummy3
dummy4
Demo
Instead of creating a Dictionary that stores an int and a list:
Dictionary<int, List<String>>
Create a Dictionary that stores the name of the list with the list:
Dictionary<string, List<String>>
If you want to then get the int number that corresponds to the list, you can use a normal for loop and see what value is at the location when let's say i = 1.

How to return a readonly copy of a collection

I have a class that contains a collection. I want to provided a method or property that returns the contents of the collection. It's ok if calling classes can modify the individual objects but I do not want them adding or removing object from the actual collection. I have been copying all the objects to a new list, but now I'm thinking that I could just return the list as IEnumerable<>.
In the simplified example below is GetListC the best way to return a read only version of a collection?
public class MyClass
{
private List<string> mylist;
public MyClass()
{
mylist = new List<string>();
}
public void Add(string toAdd)
{
mylist.Add(toAdd);
}
//Returns the list directly
public List<String> GetListA
{
get
{
return mylist;
}
}
//returns a copy of the list
public List<String> GetListB
{
get
{
List<string> returnList = new List<string>();
foreach (string st in this.mylist)
{
returnList.Add(st);
}
return returnList;
}
}
//Returns the list as IEnumerable
public IEnumerable<string> GetListC
{
get
{
return this.mylist.AsEnumerable<String>();
}
}
}
You can use List(T).AsReadOnly():
return this.mylist.AsReadOnly()
which will return a ReadOnlyCollection.
Just use ReadOnlyCollection class, it is supported since .NET 2.0
Use the generic ReadOnlyCollection class (Collection.AsReadOnly()). It doesn't copy any objects which may have some strange results when the underlying collection is changed.
var foo = new List<int> { 3, 1, 2 };
var bar = foo.AsReadOnly();
foreach (var x in bar) Console.WriteLine(x);
foo.Sort();
foreach (var x in bar) Console.WriteLine(x);
But if you don't want a copy, that's the best solution.
I prefer returning IEnumerable, but you don't need to cast. Just do
public IEnumerable<string> StringList { get { return myList; }
List<string> is an IEnumerable<string>

Categories