I have a below method which simply unnest the list within list and and create merged record all sub lists
e.g.
testResultDTO similar to
{
dept_name :'',
dept_id:'',
personList :'<List>'
}
personList is list similat to
{
first_name :'',
Last_name:'',
workHistList:'<List>'
}
workHistList is similar to
{
task_name:'',
task_description:''}
`
And the method is below
public async Task<FileDTO> GetWorkList(InputParameter inputParameter)
{
TestResultDTO testResultDTO = await GetPersonWorkList(inputParameter);
var testDto = new List<TestDto>();
if (testResultDTO != null)
{
testDto = personWorkFile(testResultDTO);
}
return testDto;
}
The problem is in method personWorkFile
private List<testDTO> personWorkFile(testResultDTO testResultDTO)
{
List<testDTO> testDTO = new List<testDTO>();
if (testResultDTO.workList is null) return new();
foreach (var testItem in testResultDTO.workList)
{
if (testItem.personList != null && testItem.personList.Any())
{
for (var j = 0; j < testItem.personList.Count; j++)
{
List<testDTO> testDTOTemp = new List<testDTO>();
for (var i = 0; i < testItem.personList[j].workHistList.Count; i++)
{
testDTOTemp.Insert(i, mapper.Map(testItem.personList[j].workHistList[i], mapper.Map<testDTO>(testItem.personList[j])));
}
testDTO.AddRange(testDTOTemp);
}
}
}
return testDTO;
}
`
what it does is it create a finale list with record similar to
{dept_name,dept_id,first_name, last_name, task_name, task_description}
Now when i create a unit test for it, it always fail because, it always insert null in list testDTOTemp.insert
my content of test case code is below
mapperMock.Setup(m => m.Map<List<TestResultDTO>, List<TestDTO>>(testResultDTO)).Returns(testDTO);
//call actual service
var result = await workService.GetWorkList(inputParameter);
Can someone please help me understand why it is not able to insert any data testDTOTemp list
The mock replays the setup by matching the method arguments. In this particular case, it will try to match the method call with the specified instance of TestResultDTO.
Override the Equals() method in TestResultDTO to let the mock compare the argument in order to return as per the setup.
Ex:
public class TestResultDTO
{
public int Id {get; set;}
}
var dto01 = new TestResultDTO(){Id = 1};
var dto02 = new TestResultDTO(){Id = 1};
dto01.Equals(dto02); // This will result in false in spite of having same Ids
If the above class is modified to
public class TestResultDTO
{
public int Id {get; set;}
public override bool Equals(object other)
{
var right = other as TestResultDTO;
if(right == null) return false;
var left = this;
var result = left.Id == right.Id;
return result;
}
}
var dto01 = new TestResultDTO(){Id = 1};
var dto02 = new TestResultDTO(){Id = 1};
dto01.Equals(dto02); // This will result in true
So my program is going to end up being fairly large and I don't want a whole lot of code that could just be shortened. Here is one instance I am looking for some tips on:
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
string books = null;
// sets books to the clicked item
books = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
// Loads string to list box and image to selectedPictureBox when programming is selected
if (books == "Programming")
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile("programming.png");
bookListBox.Items.Add("Visual Basic");
bookListBox.Items.Add("Java");
bookListBox.Items.Add("C#");
}
// Loads string to list box and image to selectedPictureBox when Networking is selected
else if (books == "Networking")
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile("networking.png");
bookListBox.Items.Add("LAN Networks");
bookListBox.Items.Add("Windows Networking");
bookListBox.Items.Add("More About Networking");
}
// Loads string to list box and image to selectedPictureBox when Web is selected
else if (books == "Web")
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile("html.png");
bookListBox.Items.Add("Web Programming");
bookListBox.Items.Add("JavaScript");
bookListBox.Items.Add("ASP");
}
}
The code works fine but I was just hoping to get some tips on shortening this code if necessary, any input is appreciated.
Assuming you can use C# 7's new Tuples:
private Dictionary<string, (string image, List<string> books)> books = new Dictionary<string, (string image, List<string> books)>
{
{ "Programming", ("programming.png", new List<string> { "Visual Basic", "Java", "C#"} ) },
{ "Networking", ("networking.png", new List<string> {"LAN Networks", "Windows Networking", "More About Networking"}) },
{ "Web", ("html.png", new List<string> {"Web Programming", "Javascript", "ASP"}) }
};
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// sets books to the clicked item
string book = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
if (books.Keys.Contains(book))
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(books[book].image);
foreach(var b in books[book].books)
{
bookListBox.Items.Add(b);
}
}
}
But a class is likely even better:
public class BookGroup
{
public string ImagePath {get;set;}
public List<string> Books {get;}
public BookGroup(string imagePath, params string[] books)
{
ImagePath = imagePath;
Books = new List<string>(books.Length);
Books.AddRange(books);
}
}
Which isn't all that different to use right now, but it formalizes some things that might make this code easier to work with down the road, and it's possible if you can't use Tuples yet. I might also have a Book class by itself, just for fun, but for now:
private Dictionary<string, BookGroup> books = new Dictionary<string, BookGroup>
{
{ "Programming", new BookGroup("programming.png", "Visual Basic", "Java", "C#")},
{ "Networking", new BookGroup("networking.png","LAN Networks", "Windows Networking", "More About Networking") },
{ "Web", new BookGroup("html.png", "Web Programming", "Javascript", "ASP") }
};
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// sets books to the clicked item
string book = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
if (books.Keys.Contains(book))
{
bookListBox.Items.Clear();
BookGroup bg = books[book];
selectedPictureBox.Image = Image.FromFile(bg.ImagePath);
foreach(var b in bg.Books)
{
bookListBox.Items.Add(b);
}
}
}
Regardless, I'd definitely have a way to load these from a text file... likely a csv, or maybe even a small in-process database, so that I could update this listing without having to recompile or distribute new program code. And, with that in mind, in order to fit this data in a single structure in a single file, I'd likely also repeat the image and type with each book, so that my csv data looks like this:
Topic,Image,Title
Programming,programming.png,"Visual Basic"
Programming,programming.png,"Java"
Programming,programming.png,"C#"
Networking,networking.png,"LAN Networks"
Networking,networking.png,"Windows Networking"
Networking,networking.png,"More About Networking"
Web,html.png,"Web Programming"
Web,html.png,"Javascript"
Web,html.png,"ASP"
That changes the whole character of the code. I'm a bit biased, but I'd likely use this CSV Parser, and again assuming Tuples I'd produce something like this:
private List<(string Topic, string ImagePath, string Title)> books;
//In the form load code:
books = EasyCSV.FromFile("bookData.csv").Select(b => (b[0], b[1], b[2])).ToList();
//and finally, in the original selectindexchanged method:
private void bookComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
string topic = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
var items = books.Where(b => b.Topic == topic).ToArray();
if(items.Length > 0)
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(items[0].ImagePath);
bookListBox.Items.AddRange(items);
}
}
Make objects and use databindings.
public class Book
{
public BookType BookType { get; set; }
public string Name { get; set; }
public string Image { get; set; }
}
public enum BookType
{
Programming,
Networking,
Web,
}
public partial class Form1 : Form
{
private readonly List<Book> _books = new List<Book>
{
new Book { Image = "programming.png", BookType = BookType.Programming, Name = "VB" },
new Book { Image = "programming.png", BookType = BookType.Programming, Name = "Java" },
new Book { Image = "programming.png", BookType = BookType.Programming, Name = "C#" },
new Book { Image = "networking.png", BookType = BookType.Networking, Name = "LAN Networks" },
new Book { Image = "networking.png", BookType = BookType.Networking, Name = "Windows Networking" },
new Book { Image = "networking.png", BookType = BookType.Networking, Name = "More About Networking" },
new Book { Image = "html.png", BookType = BookType.Web, Name = "Web Programming" },
new Book { Image = "html.png", BookType = BookType.Web, Name = "Javascript" },
new Book { Image = "html.png", BookType = BookType.Web, Name = "ASP" },
};
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var bookTypes = _books.GroupBy(b => b.BookType).Select(g => g.Key).ToList();
this.cboBookTypes.DataSource = bookTypes;
}
private void cboBookTypes_SelectedIndexChanged(object sender, EventArgs e)
{
var bookType = (BookType)this.cboBookTypes.SelectedItem;
var books = _books.Where(b => b.BookType == bookType).ToList();
var img = books.First().Image;
this.imgBook.Image = Image.FromFile(img);
this.lstBooks.DataSource = books;
this.lstBooks.DisplayMember = "Name";
}
}
If you are talking about the length of the code, I would suggest using switch-case-break-default construct
Switch the books variable.
This wont improve the performance though
I think you should create a class that represents book category. Then, you could simply iterate through all the category lists and extract the necessary information, like this:
string books = null;
books = bookComboBox.SelectedItem.ToString();
selectedPictureBox.Visible = true;
for (int i = 0; i < categories.Count; i++) {
if (books == categories[i].Name) {
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(categories[i].ImagePath);
for (int j = 0; j < categories[i].Items.Count; j++) {
bookListBox.Items.Add(categories[i].Items[j]);
}
}
}
I would suggest to keep all the data in a configuration object and then iterate through that data when performing checks and assignments.
I would create a separate class to hold data for each book: name, picture file name and check box items string array.
Then I would create a list of that object and assign all the data manually on form initialization.
After that, in SelectedIndexChanged event handler, I would iterate (for loop) on each item and check if the book name matched. If it did, then I would use data from that object and then break; the loop.
I do not have visual studio, so giving you the points/suggestions to improve on.
switch should be preferred over if-elseif.
bookListBox.Items.Clear(); and selectedPictureBox.Image out of if block. Use a variable to set the image file name.
Create a class to represent a book list:
public class BookList
{
public string ImageName { get; set; }
public List<string> Items { get;set; }
}
Then create a dictionary to hold these items:
Dictionary<string, BookList> bookLists = new Dictionary<string, BookList>
{
{
"Programming",
new BookList { ImageName = "programming.png", Items = new List<string> { ... } }
}
...
};
Then modify your if statements to:
if (bookLists.ContainsKey(books))
{
bookListBox.Items.Clear();
selectedPictureBox.Image = Image.FromFile(bookLists[books].ImageName);
foreach (var b in bookLists[books].Items)
{
bookListBox.Items.Add(b);
}
}
I need to determine the hierarchy level to display a tree, I don't need to link relationships at the moment, I have a list of objects as follows:
public class ObjectData
{
public string ID;
public string hierarchyParent;
public int hierarchyLevel;
}
I need to set the hierarchyLevel integer based on its row level. The hierarchyParent var contains the ID of its parent. I don't know how wide each column would be nor how many rows, so it needs to be dynamic with the hierarchy level integer either ascending or descending. So far, I have been able to determine the top row but am unsure how to continue, any help would be appreciated! So far:
List<ObjectData> Sort(List<ObjectData> objectToBeSorted){
List<ObjectData> returnlist = new List<ObjectData>();
string topObject = null;
foreach(ObjectData obj in objectToBeSorted)
{
if(obj.hierarchyParent == null){
topObject = obj.ID;
obj.hierarchyLevel = 1;
}
}
foreach(ObjectData obj in objectToBeSorted)
{
if(obj.hierarchyParent == topObject){
}
}
return returnlist;
}
Here's a quick try with sample data and recursive calls :
The useful part is is in AssignChild method.
public class ObjectData
{
public string ID;
public string hierarchyParent;
public int hierarchyLevel;
}
void Main()
{
var objects = new List<ObjectData>() {
new ObjectData() { ID = "Obj12", hierarchyParent = null },
new ObjectData() { ID = "Obj5", hierarchyParent = "Obj12" },
new ObjectData() { ID = "Obj9", hierarchyParent = "Obj12" },
new ObjectData() { ID = "Obj7", hierarchyParent = "Obj5" },
new ObjectData() { ID = "Obj99", hierarchyParent = "Obj58" },
new ObjectData() { ID = "Obj58", hierarchyParent = "Obj5" } };
ObjectData top = objects.Find(p => p.hierarchyParent == null);
top.hierarchyLevel = 1;
AssignChild(objects, top);
objects.Dump();
}
void AssignChild(List<ObjectData> all, ObjectData parent)
{
var child = all.FindAll(o => o.hierarchyParent == parent.ID);
child.ForEach(c => { c.hierarchyLevel = parent.hierarchyLevel +1; AssignChild(all, c); });
}
It can probably be optimized but it should work.
I suggest doing something like this:
public int GetHierarchyLevel(ObjectData obj, IEnumerable<ObjectData> allObjects)
{
if(obj.hierarchyParent == null)
return 1;
else
return 1 + GetHierarchyLevel(allObjects.First(o=>o.ID == obj.hierarchyParent));
}
Of course, you should integrate this into your classes so that you can possibly replace the arguments by class members. Also, please notice that some error checking may be required. It is just meant to give you an idea of an algorithm.
For performance, I suggest a caching mechanism. Like initializing hierarchyLevel to -1 and using the following modification:
public int GetHierarchyLevel(ObjectData obj, IEnumerable<ObjectData> allObjects)
{
if (obj.hierarchyLevel != -1)
return obj.hierarchyLevel;
if(obj.hierarchyParent == null)
return 1;
else
return 1 + GetHierarchyLevel(allObjects.First(o=>o.ID == obj.hierarchyParent));
}
Of course, this would require invalidating all cached results when you want to recalculate after a change in the structure of your hierarchy.
I want to learn classes atm and here is what I came up with:
Class level to create a level. This class has an object array that fills itself with rooms (raeume) which is the other class. Now, I want to access the objects in the object array from room, after I inserted them. Here is what I want to type:
wohnung.rooms[i].raumname.toString();
Here are the two classes
class raum
{
static object[] o_nebenraum = new object[3]; //N-O-S-W
static string s_raumname = "";
public object[] nebenraume
{
get
{
return o_nebenraum;
}
set
{
o_nebenraum = value;
}
}
public string raumname
{
get
{
return s_raumname;
}
set
{
s_raumname = value;
}
}
}
class level
{
static object[] o_rooms = new object[100];
public object[] rooms
{
get
{
return o_rooms;
}
set
{
o_rooms = value;
}
}
}
Here is how I set everything up.
level wohnung = new level();
raum keller = new raum();
raum wohnzimmer = new raum();
raum kueche = new raum();
raum schlafzimmer = new raum();
wohnung.rooms[0] = keller;
wohnung.rooms[1] = wohnzimmer;
wohnung.rooms[2] = kueche;
wohnung.rooms[3] = schlafzimmer;
keller.raumname = "Keller";
wohnzimmer.raumname = "Wohnzimmer";
kueche.raumname = "Küche";
schlafzimmer.raumname = "Schlafzimmer";
for (uint i = 0; i < 3; i++)
{
Console.WriteLine("Wohnung beinhaltet jetzt " + *MISSING CODE PART, I WANT TO GET THE .raumname out of the object array from wohnung.room*);
}
Console.ReadKey();
You have to use generic typed list List<T> (See on MSDN) instead of array, in this case you'll have the indexed access for the typed list elements
So instead of:
static object[] o_rooms = new object[100];
public object[] rooms
Use:
static IList<raum> o_rooms = new List<Raum>(100);
public IList<raum> rooms
Try this(in the for Loop):
Console.WriteLine("Wohnung beinhaltet jetzt " + (wohnung.rooms[i] as raum).raumname );
You would be better off using generics though in which case the class level would now look like:
class level
{
static List<raum> o_rooms = new List<raum>();
public List<raum> rooms
{
get { return o_rooms; }
set { o_rooms = value; }
}
}
and the for loop can be replaced with a foreach loop as follows:
foreach(raum room in wohnung.rooms)
{
Console.WriteLine("Wohnung beinhaltet jetzt " + room.raumname );
}
my Linq query is.
string spouseName="jenny";
var empData = from sData in EmpList
from member in sData.familyNames
where string.Compare(member, spouseName, true) == 0
select new Employee
{
CompanyDept = sData.company,
EmpName = sData.empName,
FamilyNames.Add(spouse) //ERROR HERE Not able to access as list
};
Here empList is List<Employee>
class Employee
{
private string companyDept
private string empName
private List<string> _familyNames = new List<string>();
public string CompanyDept
{
get { return companyDept}
set { companyDept= value; }
}
public string EmpName
{
get { return empName}
set { empName= value; }
}
public List<string> FamilyNames
{
get { return _familyNames }
set { _familyNames = value; }
}
}
Question:
Here I am trying to get a linq output as of type Employee... but the list familyNames contains only one item spouse name, not list of all family members.??
But I am getting error at familyList. Not able to add items to familyNames List to not able to assign.
Need help, why error is comming or I am wrong somewhere?
The correct translation is:
select new Employee
{
CompanyDept = sData.company,
EmpName = sData.empName,
FamilyNames = { spouse } // 'nested' collection-initializer
};
The reason is that you only need an Add call on FamilyMember, not a full property reassignment to a new list, which is what FamilyNames = new List<string> { spouse } would do.
Loosely speaking, this translates to:
var temp = new Employee();
temp.CompanyDept = sData.company;
temp.EmpName = sData.empName;
temp.FamilyNames.Add(spouse);
return temp; // this is selected.
You need to initialize the list yourself. Change:
FamilyNames.Add(spouse)
To:
FamilyNames = new List<string>(new []{ spouse })
It should be something like
select new Employee
{
CompanyDept = sData.company,
EmpName = sData.empName,
// FamilyNames.Add(spouse) //ERROR HERE Not able to access as list
FamilyNames = new List<string> {spouse}
} ;
Although I would have expected sData.spouse or member.spouse