Populate a list in constructor - c#

I'm looking for the better way to initialize a list directly in the constructor of my object. The goal is to put the initialize code at the same place, without taking several many lines.
public class Object1
{
public string data1 { get; set; }
public string data2 { get; set; }
public List<Object2> myList { get; set; }
}
public class Object2
{
public int Id { get; set; }
public string myData { get; set; }
}
public class Object3
{
public int Id { get; set; }
public string myOtherData { get; set; }
}
There is my way in order to initialize myList from Objet1 :
public static void myProgram()
{
List<Object3> test = new List<Object3>
{
new Object3
{
Id = 1,
myOtherData = "blabla"
},
new Object3
{
Id = 8,
myOtherData = "blabla"
}
};
/* That is what I do now */
Object1 myObject = new Object1
{
data1 = "toto",
data2 = "titi",
myList = test != null && test.Count > 0 ? new List<Object2>() : null
};
foreach (Object3 obj3 in test)
{
if (obj3.Id > 3)
{
myObject.myList.Add(new Object2
{
Id = obj3.Id,
myData = $"lol {obj3.myOtherData}"
});
}
}
}
I'm looking for a way which avoid to use a foreach after construction of my object. Something like this :
/* That is what I try to do */
Object1 myObject = new Object1
{
data1 = "toto",
data2 = "titi",
myList = test != null && test.Count > 0 ? new List<Object2>().AddRange( /* PUT THE FOREACH HERE */)
}
I think we can use lambda / delegates in order to create anonymous function which will fill the list, but I don't how it works.
}

You can do it with Linq.
myList = test?.Where(x => x.Id > 3).Select(x => new Object2
{
Id = x.Id,
myData = $"lol {x.myOtherData}"
}).ToList()

Related

Automapper: same instance after mapping

I try Automapper and it is very nice but is it possible map two OuterDto source to OuterModel destination with same object InnerDeto like in code? How can I do that dest1.Inner and dest2.Inner after map has same instance? What I know, I think it is not possible. What do you think? Thanks for help me
public class OuterDto
{
public int Value { get; set; }
public InnerDto Inner { get; set; }
}
public class InnerDto
{
public int OtherValue { get; set; }
}
public class OuterModel
{
public int Value { get; set; }
public InnerModel Inner { get; set; }
}
public class InnerModel
{
public int OtherValue { get; set; }
}
public class test
{
public test()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<InnerDto, InnerModel>().ReverseMap();
cfg.CreateMap<OuterDto, OuterModel>().ReverseMap();
});
config.AssertConfigurationIsValid();
InnerDto innerSource = new InnerDto { OtherValue = 15 };
var source1 = new OuterDto
{
Value = 1,
Inner = innerSource
};
var source2 = new OuterDto
{
Value = 2,
Inner = innerSource
};
var mapper = config.CreateMapper();
source1.Inner.OtherValue = 20;
var dest1 = mapper.Map<OuterDto, OuterModel>(source1);
var dest2 = mapper.Map<OuterDto, OuterModel>(source2);
dest1.Inner.OtherValue = 1000;
//Result:
//dest1.Inner.OtherValue = 1000
//dest2.Inner.OtherValue = 20
//Expected Result:
//dest1.Inner.OtherValue = 1000
//dest2.Inner.OtherValue = 1000
}
}
I'm not sure, but try to instanciate OuterModel before calling Map method
//...
var mapper = config.CreateMapper();
source1.Inner.OtherValue = 20;
var dest1 = new OuterModel();
mapper.Map(source1, dest1);
mapper.Map(source2, dest1);
dest1.Inner.OtherValue = 1000;
NOTE: I haven't tested my code, it's just to give food for thought

Converting table in tree

Is there any scope for improvement in my program which converts flat db entity to a tree data structure.
I don't want to loose the Generic flexibility as i should be able to use the same method for any other DBEntity class
Interface for db entity class
public interface IDbEntityNode
{
int Id { get; set; }
int ParentId { get; set; }
}
Example of db Entity class
public class ExceptionCategory :IDbEntityNode
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
Generic class which holds the structure of tree node
public class GenericNode<T>
{
public T NodeInformation { get; set; }
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; } = new List<GenericNode<T>>();
}
Method which coverts flat list to tree
public static List<GenericNode<T>> CreateGenericTree<T>(List<T> flatDataObject,Func<T,bool> IsRootNode) where T : IDbEntityNode
{
var lookup = new Dictionary<int, GenericNode<T>>();
var rootNodes = new List<GenericNode<T>>();
var noOfElements = flatDataObject.Count;
for (int element = 0; element < noOfElements; element++)
{
GenericNode<T> currentNode;
if (lookup.TryGetValue(flatDataObject[element].Id, out currentNode))
{
currentNode.NodeInformation = flatDataObject[element];
}
else
{
currentNode = new GenericNode<T>() { NodeInformation = flatDataObject[element] };
lookup.Add(flatDataObject[element].Id, currentNode);
}
if (IsRootNode(flatDataObject[element]))
{
rootNodes.Add(currentNode);
}
else
{
GenericNode<T> parentNode;
if (!lookup.TryGetValue(flatDataObject[element].ParentId, out parentNode))
{
parentNode = new GenericNode<T>();
lookup.Add(flatDataObject[element].ParentId, parentNode);
}
parentNode.Children.Add(currentNode);
currentNode.Parent = parentNode;
}
}
return rootNodes;
}
Execution:
private static void Main(string[] args)
{
List<IDbEntityNode> flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
var tree = CreateGenericTree(flatDataStructure, IsRootNode);
}
private static bool IsRootNode(IDbEntityNode dbEntity)
{
bool isRootNode = false;
if (dbEntity.ParentId == 0 )
isRootNode = true;
return isRootNode;
}
Created a generic approach, table objects need to follow the dbSet interface and TreeNode objects need to follow the ITreeNode. I used binarySerach to make this as fast as possible. No recursion needed. The logic ensures that you do not need to have the items in a particular order. I did not throw an error when out of the loop when there are still unassigned objects, this can be easy added.
using System.Collections.Generic;
public interface ITreeNode
{
string ParentId { get; set; }
string Id { get; set; }
dbItem item { get; set; }
List<ITreeNode> Nodes { get; set; }
}
public class TreeNode : ITreeNode
{
public TreeNode()
{ }
public string ParentId { get; set; }
public string Id { get; set; }
public dbItem item { get; set; }
public List<ITreeNode> Nodes { get; set; }
}
public class dbItem
{
public string ParentId { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
class app
{
static void Main()
{
List<dbItem> dbSet = new List<dbItem>();
dbSet.Add(new dbItem() { Id = "5", ParentId = "1", Name = "Jan" });
dbSet.Add(new dbItem() { Id = "25", ParentId = "1", Name = "Maria" });
dbSet.Add(new dbItem() { Id = "1", Name = "John" });
dbSet.Add(new dbItem() { Id = "8", ParentId = "2", Name = "Cornelis" });
dbSet.Add(new dbItem() { Id = "2", Name = "Ilse" });
dbSet.Add(new dbItem() { Id = "3", Name = "Nick" });
dbSet.Add(new dbItem() { Id = "87", ParentId = "5", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "67", ParentId = "3000", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "3000", Name = "Max" });
List<TreeNode> result = BuildTree<TreeNode>(dbSet);
}
private class ParentComparer<T> : IComparer<ITreeNode> where T: ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
if (x.ParentId == null) return -1; //have the parents first
return x.ParentId.CompareTo(y.ParentId);
}
}
private class IdComparer<T> : IComparer<ITreeNode> where T : ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
return x.Id.CompareTo(y.Id);
}
}
static private List<T> BuildTree<T> (List<dbItem> table) where T: ITreeNode, new()
{
//temporary list of tree nodes to build the tree
List<T> tmpNotAssignedNodes = new List<T>();
List<T> tmpIdNodes = new List<T>();
List<T> roots = new List<T>();
IComparer<T> pc = (IComparer<T>) new ParentComparer<T>();
IComparer<T> ic = (IComparer<T>) new IdComparer<T>();
foreach (dbItem item in table)
{
T newNode = new T() { Id = item.Id, ParentId = item.ParentId, item = item };
newNode.Nodes = new List<ITreeNode>();
T dummySearchNode = new T() { Id = item.ParentId, ParentId = item.ParentId };
if (string.IsNullOrEmpty(item.ParentId))
roots.Add(newNode);
else
{
int parentIndex = tmpIdNodes.BinarySearch(dummySearchNode, ic);//Get the parent
if (parentIndex >=0)
{
T parent = tmpIdNodes[parentIndex];
parent.Nodes.Add(newNode);
}
else
{
parentIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
if (parentIndex < 0) parentIndex = ~parentIndex;
tmpNotAssignedNodes.Insert(parentIndex, newNode);
}
}
dummySearchNode.ParentId = newNode.Id;
//Cleanup Unassigned
int unAssignedChildIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
while (unAssignedChildIndex >= 0 && unAssignedChildIndex < tmpNotAssignedNodes.Count)
{
if (dummySearchNode.ParentId == tmpNotAssignedNodes[unAssignedChildIndex].ParentId)
{
T child = tmpNotAssignedNodes[unAssignedChildIndex];
newNode.Nodes.Add(child);
tmpNotAssignedNodes.RemoveAt(unAssignedChildIndex);
}
else unAssignedChildIndex--;
}
int index = tmpIdNodes.BinarySearch(newNode, ic);
tmpIdNodes.Insert(~index, newNode);
}
return roots;
}
}
Try following solution using recursive code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public static List<IDbEntityNode> flatDataStructure = null;
public static Dictionary<int?, List<IDbEntityNode>> dict = null;
static void Main(string[] args)
{
flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
dict = flatDataStructure.GroupBy(x => x.ParentId, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
GenericNode<IDbEntityNode> root = new GenericNode<IDbEntityNode>();
root.Parent = null;
int rootId = 0;
root.NodeInformation.Id = rootId;
root.NodeInformation.name = "root";
root.NodeInformation.ParentId = null;
CreateGenericTree(root);
}
public static void CreateGenericTree<T>(GenericNode<T> parent) where T : IDbEntityNode, new()
{
if (dict.ContainsKey(parent.NodeInformation.Id))
{
List<IDbEntityNode> children = dict[parent.NodeInformation.Id];
foreach (IDbEntityNode child in children)
{
GenericNode<T> newChild = new GenericNode<T>();
if (parent.Children == null) parent.Children = new List<GenericNode<T>>();
parent.Children.Add(newChild);
newChild.NodeInformation.Id = child.Id;
newChild.NodeInformation.ParentId = parent.NodeInformation.Id;
newChild.NodeInformation.name = child.name;
newChild.Parent = parent;
CreateGenericTree(newChild);
}
}
}
}
public class GenericNode<T> where T : new()
{
public T NodeInformation = new T();
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; }
}
public class IDbEntityNode
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string name { get; set; }
}
public class ExceptionCategory : IDbEntityNode
{
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
}

Casting List Type at Runtime C# Reflection

I've been working on using reflection but its very new to me still. So the line below works. It returns a list of DataBlockOne
var endResult =(List<DataBlockOne>)allData.GetType()
.GetProperty("One")
.GetValue(allData);
But I don't know myType until run time. So my thoughts were the below code to get the type from the object returned and cast that type as a list of DataBlockOne.
List<DataBlockOne> one = new List<DataBlockOne>();
one.Add(new DataBlockOne { id = 1 });
List<DataBlockTwo> two = new List<DataBlockTwo>();
two.Add(new DataBlockTwo { id = 2 });
AllData allData = new AllData
{
One = one,
Two = two
};
var result = allData.GetType().GetProperty("One").GetValue(allData);
Type thisType = result.GetType().GetGenericArguments().Single();
Note I don't know the list type below. I just used DataBlockOne as an example
var endResult =(List<DataBlockOne>)allData.GetType() // this could be List<DataBlockTwo> as well as List<DataBlockOne>
.GetProperty("One")
.GetValue(allData);
I need to cast so I can search the list later (this will error if you don't cast the returned object)
if (endResult.Count > 0)
{
var search = endResult.Where(whereExpression);
}
I'm confusing the class Type and the type used in list. Can someone point me in the right direction to get a type at run time and set that as my type for a list?
Class definition:
public class AllData
{
public List<DataBlockOne> One { get; set; }
public List<DataBlockTwo> Two { get; set; }
}
public class DataBlockOne
{
public int id { get; set; }
}
public class DataBlockTwo
{
public int id { get; set; }
}
You might need something like this:
var endResult = Convert.ChangeType(allData.GetType().GetProperty("One").GetValue(allData), allData.GetType());
Just guessing, didn't work in C# since 2013, please don't shoot :)
You probably want something like this:
static void Main(string[] args)
{
var one = new List<DataBlockBase>();
one.Add(new DataBlockOne { Id = 1, CustomPropertyDataBlockOne = 314 });
var two = new List<DataBlockBase>();
two.Add(new DataBlockTwo { Id = 2, CustomPropertyDatablockTwo = long.MaxValue });
AllData allData = new AllData
{
One = one,
Two = two
};
#region Access Base Class Properties
var result = (DataBlockBase)allData.GetType().GetProperty("One").GetValue(allData);
var oneId = result.Id;
#endregion
#region Switch Into Custom Class Properties
if (result is DataBlockTwo)
{
var thisId = result.Id;
var thisCustomPropertyTwo = ((DataBlockTwo)result).CustomPropertyDatablockTwo;
}
if (result is DataBlockOne)
{
var thisId = result.Id;
var thisCustomPropertyOne = ((DataBlockOne)result).CustomPropertyDataBlockOne;
}
#endregion
Console.Read();
}
public class AllData
{
public List<DataBlockBase> One { get; set; }
public List<DataBlockBase> Two { get; set; }
}
public class DataBlockOne : DataBlockBase
{
public int CustomPropertyDataBlockOne { get; set; }
}
public class DataBlockTwo : DataBlockBase
{
public long CustomPropertyDatablockTwo { get; set; }
}
public abstract class DataBlockBase
{
public int Id { get; set; }
}

Group items by content of list

Lets say i got a something like this:
public class Subscriber{
public string Name {get; set;}
}
public class SomeData{
public string Content {get; set;}
}
public class InputData {
public Subscriber Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
}
public class QueueItem {
public IEnumerable<Subscriber> Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
}
Now lets say i get a List<InputData> full of "Subscribers" with a list of data for each subscriber.
Now i want to compare the list of data of each subscriber, and end up with a List<QueueItem>, where if 2 subscribers have the same set of data items, they would be 1 QueueItem.
Hope this makes sense
The technique is using EqualityComparer with Enumerable.SequenceEqual()
public class Subscriber
{
public string Name { get; set; }
// For compare
public override bool Equals(object obj) { return string.Equals(this.Name, ((Subscriber)obj).Name); }
public override int GetHashCode() { return this.Name.GetHashCode(); }
}
public class SomeData
{
public string Content { get; set; }
// For compare
public override bool Equals(object obj) { return string.Equals(this.Content, ((SomeData)obj).Content); }
public override int GetHashCode() { return this.Content.GetHashCode(); }
}
public class InputData
{
public Subscriber Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
// Should always initialize an empty collection
public InputData() { this.DataItems = new List<SomeData>(); }
}
public class QueueItem
{
public IEnumerable<Subscriber> Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
// Should always initialize an empty collection
public QueueItem() { this.Subscribers = new List<Subscriber>(); this.DataItems = new List<SomeData>(); }
}
public class DataItemsEqualityComparer : EqualityComparer<IEnumerable<SomeData>>
{
public override bool Equals(IEnumerable<SomeData> x, IEnumerable<SomeData> y)
{
return Enumerable.SequenceEqual(x.OrderBy(i => i.Content), y.OrderBy(i => i.Content));
}
public override int GetHashCode(IEnumerable<SomeData> obj)
{
return obj.Select(i => i.GetHashCode()).Sum().GetHashCode();
}
}
Usage
var data = new List<InputData>();
var fruits = new[] { new SomeData() { Content = "apple" }, new SomeData() { Content = "pear"} };
var colors = new[] { new SomeData() { Content = "red" }, new SomeData() { Content = "blue" }, new SomeData() { Content = "green" } };
data.Add(new InputData() { Subscribers = new Subscriber() { Name = "Alice" }, DataItems = new List<SomeData>(fruits) });
data.Add(new InputData() { Subscribers = new Subscriber() { Name = "Bob" }, DataItems = new List<SomeData>(colors) });
data.Add(new InputData() { Subscribers = new Subscriber() { Name = "Charlie" }, DataItems = new List<SomeData>(fruits) });
List<QueueItem> groupedData = data.GroupBy(
i => i.DataItems,
i => i.Subscribers,
new DataItemsEqualityComparer())
.Select(i => new QueueItem() { Subscribers = i, DataItems = i.Key }).ToList();
Result
QueueItem :
Subscribers:
- Alice
- Charlie
Data:
- apple
- pear
QueueItem :
Subscribers:
- Bob
Data:
- red
- blue
- green
var queue = Dictionary(Subscriber, List<SomeData>);
//And lets just for example add some data
var items1 = new List<SomeData>();
items1.Add(new SomeData("test"));
items1.Add(new SomeData("test2"));
var items2 = new List<SomeData>();
items2.Add(new SomeData("test"));
queue.Add(new Subscriber("Peter"), items1);
queue.Add(new Subscriber("Luke"), items1);
queue.Add(new Subscriber("Anna"), items2);
Dictionary<Subscriber, List<SomeData>> myDictionary = queue
.GroupBy(o => o.PropertyName)
.ToDictionary(g => g.Key, g => g.ToList());

How merge two lists of different objects?

Using C# with LINQ, how can I merge two lists of different objects, say, Seminar and Conference?
They have some common and some different fields/properties and do not share unique id.
class Seminar
{
int id,
DateTime joinDate,
string name
}
class Conference
{
Guid confNumber,
DateTime joinDate
Type type
}
I have a list of:
List<Seminar>
List<Conference>
I need to merge them into a super List:
List<Object>
A code snippet would be great help.
If you just want a single List<object> containing all objects from both lists, that's fairly simple:
List<object> objectList = seminarList.Cast<object>()
.Concat(conferenceList)
.ToList();
If that's not what you want, then you'll need to define what you mean by "merge".
Following code works fine for me, if this is your definition of Merge
One solution
List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = new A() } };
List<Object> allS = (from x in someAs select (Object)x).ToList();
allS.AddRange((from x in someBs select (Object)x).ToList());
Where A and B are some classes as follows
class A
{
public string someAnotherThing { get; set; }
}
class B
{
public A something { get; set; }
}
Another Solution
List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = string.Empty } };
List<Object> allS = (from x in someAs select (Object)new { someAnotherThing = x.someAnotherThing, something = string.Empty }).ToList();
allS.AddRange((from x in someBs select (Object)new { someAnotherThing = string.Empty, something = x.something}).ToList());
Where A and B are having class definition as
class A
{
public string someAnotherThing { get; set; }
}
class B
{
public string something { get; set; }
}
Simple method of pure code
internal class Person
{
public int Id { get; set; }
public string UserName { get; set; }
}
internal class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
internal class UserPerson
{
public int Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
private static void Main(string[] args)
{
Person[] people = new Person[3] { new Person { Id = 1, UserName = "AliUserName" }, new Person { Id = 2, UserName = "MortezaUserName" }, new Person { Id = 3, UserName = "SalarUserName" } };
User[] users = new User[4] { new User { FirstName = "ali", LastName = "Barzegari" }, new User { FirstName = "Morteza", LastName = "Sefidi" }, new User { FirstName = "Salar", LastName = "Pirzadeh" }, new User { FirstName = "Babak", LastName = "Hasani" } };
UserPerson[] userPeople = new UserPerson[people.Length > users.Length ? people.Length : users.Length];
if (people.Length > users.Length)
for (int i = 0; i < people.Length; i++)
{
userPeople[i] = new UserPerson
{
Id = people[i].Id,
UserName = people[i].UserName,
FirstName = users.Length <= i ? "" : users[i].FirstName,
LastName = users.Length <= i ? "" : users[i].LastName
};
}
else
for (int i = 0; i < users.Length; i++)
{
userPeople[i] = new UserPerson
{
Id = people.Length <= i ? 0 : people[i].Id,
UserName = people.Length <= i ? "" : people[i].UserName,
FirstName = users[i].FirstName,
LastName = users[i].LastName
};
}
Console.ReadLine();
}

Categories