Join the data of different Lists present in different classes - c#

public class EmpManagement
{
public List<Employee> empList = new List<Employee>();
//Method for adding new employee
public void AddEmp(Employee emp)
{
empList.Add(emp);
}
public void displayEmp(Employee emp)
{
Console.WriteLine("[" + emp.Empname + "]");
}
//Method for viewing all employees
public void ShowEmp()
{
foreach (var e in empList)
{
displayEmp(e);
}
}
}
public class Role
{
public string RoleName { get; set; }
public Role(string roleName)
{
RoleName = roleName;
}
}
public class RoleManagement
{
public List<Role> RoleList = new List<Role>();
//Method for adding roles
public void RoleAdd(Role role)
{
RoleList.Add(role);
}
//Method for viewing all roles
public void displayRole()
{
foreach (var e in RoleList)
{
Console.WriteLine(e.RoleName);
}
}
}
Join the above two lists in a different class
How can i add below two Lists into another list of different class
I am facing a problem while using a interface in one class and extending into the new class
I am also unable to use contains keyword, the compiler says that the name does not exist in current context

First, declare two lists and join these two in another list.
Please check the example below
List <string> list1 = new List <string>(){"L1L1","L1L2","L1L3"};
List <string> list2 = new List <string>(){"L2L1","L2L2","L2L3"};
List<string> joinList = list1.Join(list2);
Please see another example which is given below.
public class Role
{
public string name { get; set; }
}
public class Role2
{
public string name { get; set; }
}
public class RoleManagement
{
public List<Role> r1 = new List<Role>();
public List<Role> r2 = new List<Role>();
List<string> joinList2 = r1.Join(r2);
}

You cannot join two lists of different types into a single list. But you could still take casting into consideration, and cast the two data types into a single data type and then join the two lists into a single list.
for more information, you could refer to the following :
https://linuxhint.com/csharp-combine-two-lists/#:~:text=We%20will%20demonstrate%20an%20example,cs%E2%80%9D%20extension.

Related

How can I properly define the number of different objects to create?

I have this class with these two methods and a list:
public class Example
{
protected List<Person> ExampleList = new List<Person>();
public Example()
{
CreatePersonInstances();
foreach (Person personToInitialize in ExampleList)
personToInitialize.Initialize();
}
protected void CreatePersonInstances()
{
ExampleList.Add(new Employee());
ExampleList.Add(new Manager());
ExampleList.Add(new Recruiter());
}
}
How can I create properly a specific number of items from a user defined quantity?
For example, if the user decides to create two employees, a manager and zero recruiters, I have to be able to create the defined quantity of objects in CreatePersonInstaces();
protected void CreatePersonInstances(int employeeCount, int managerCount, int recruiterCount)
{
//some validation to check count number not negative
ExampleList.AddRange(Enumerable.Range(0, employeeCount).Select(x => new Employee()));
ExampleList.AddRange(Enumerable.Range(0, managerCount).Select(x => new Manager()));
ExampleList.AddRange(Enumerable.Range(0, recruiterCount).Select(x => new Recruiter()));
}
where Employee, Manager and recruiter inherit from Person entity
public class Person
{
public string Name { get; set; }
}
public class Employee : Person
{
public int EmployeeId { get; set; }
}
public class Manager : Person
{
public int ManagerId { get; set; }
}
public class Recruiter : Person
{
public int RecruiterId { get; set; }
}
Besides the scope of the question, this whole model is a good use case for the Factory Design Pattern. If you havent, check it out đź‘Ť
You could begin by adding 3 parameters in the constructor, - a parameter each signifying number of Employee/Manager/Recruiter to create.
public Example(int employee,int manager,int Recruiter)
{
// Rest of code
}
You could also make your CreatePersonInstances method generic that accepts a parameter type which inherits from Person along with number of instances to create.
protected void CreatePersonInstances<T>(int count) where T:Person,new()
{
EmployeeList.AddRange(IEnumerable.Range(1,count).Select(x=>new T()));
}
You could now change your constructor definition as
public Example(int employeeCount,int managerCount,int recruiterCount)
{
CreatePersonInstances<Employee>(employeeCount);
CreatePersonInstances<Manager>(managerCount);
CreatePersonInstances<Recruiter>(recruiterCount);
foreach (Person personToInitialize in ExampleList)
personToInitialize.Initialize();
}

Why do I get different object form same source by different way?

I create a static class that includes the definition of global variables and functions, but maybe it is wrong.
I need to crete a shopping cart, after refreshing,the content shouldn't be lost.
In staic class A, I create a staic variables ObservableCollection Collection1 and Collection2(Collection1 have children but Collection2) and staic functions Refresh() used to refresh Collection1.
In dynamic class B, I get some children and add them to Collection2, then use A.Refresh(), in the process of refreshing, if the new data have same id as any one in old Collection2, add it in new Collection2.
public class Model
{
public Guid Id{ get; set; }
public string Name{ get; set; }
}
public static class A
{
public static ObservableCollection<Model> Collection1 { get; set; } = new ObservableCollection<Model>();
public static ObservableCollection<Model> Collection2 { get; set; } = new ObservableCollection<Model>();
public static Refresh()
{
var uidList = Collection2.Select(x => x.Id).ToList();
Collection1.Clear();
Collection2.Clear();
foreach (var item in dataFromServer)
{
var newModel = new Model{Id = item.Id};
Collection1.Add(newModel);
if(uidList.Contains(item.Id))
{
Collection2.Add(newModel);
}
}
}
}
public class B
{
public B()
{
A.Refresh();
}
public AddToCart(Guid id)
{
var model = A.Collection1.First(x=>x.Id == id);
if (!A.Collection2.Contains(model))
{
A.Collection2.Add(model);
}
}
public Refresh()
{
A.Refresh();
}
}
I used B.AddToCart(AAAA) to add a child to Collection2,then used B.Refresh(),now I have new data form server,a new object(Id is AAAA) in Collection1 and Collection2.Then I used B.AddToCart(AAAA) again,now Collection2 have two children with same Id and Name,even I change one of the,the other one's name changed too.It's meaning there are same two object in Collection2 right?But why does A.Collection2.Contains(model) return false?I used Object.ReferenceEquals to check the two children,the result is false,too.
I konw Collection2.Any(x=>x.Id==id) can be worked,I just want to konw how it happened.
Edit:I create a demo,but he problem did not recur,maybe something wrong in other part.
You need to implement IEquatable<Model> on your Model class.
This is a duplicate question, REF: ObservableCollection.Contains() Doesn't Work Correctly

Object’s Parent Current Instance

Having the following object(s):
public class Employee
{
public string LastName { get; set; } = "";
internal class SubordinateList<T> : List<T>, IPublicList<T> where T : Employee
{
public new void Add(T Subordinate) { }
}
public IPublicList<Employee> Subordinates = new SubordinateList<Employee>();
}
The SubordinateList object is inside the Employee object making Employee the parent of SubordinateList in a certain way.
If we put this code below:
Anakin = New Employee();
Luke = New Employee();
Anakin.Subordinates.Add(Luke);
The third line will trigger the method “Add” of SubordinateList.
I would like to get the Current Instance for the Parent of SubordinateList like this:
public new void Add(T Subordinate)
{
T Manager = Subordinate.ParentInstance;
// then it will be possible to see the current value of
// the property "LastName" for Anakin with "Manager.LastName"
}
You can't do it that way since you don't have a reference to the manager. This is how I would implement it:
public class Employee
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public string HiredDate { get; set; } = "";
private List<Employee> _subordinates = new List<Employee>();
public ReadOnlyCollection<Employee> Subordinates => _subordinates.AsReadOnly();
public void AddSubordinate(Employee employee)
{
_subordinates.Add(Employee);
//the manager is 'this'
var managerLastName = this.LastName;
}
}
Exposing the subordinate list as a ReadOnlyCollection allows other classes to read the list, but prevents them from updating the list directly. So only the AddSubordinate() method can be used to add employees, where you can do what you need with the manager's information.

Dynamic properties in LINQ query

I'm trying to convert a complex domain model into a CSV format. However the dynamic structure of the model is pushing my LINQ wizardry to its limit :)
The desired result should look something like the following. A header row, then data rows.
Note that some fields are empty and others have multiple.
Output
PropA;RolenameA;RolenameB;RolenameC
123;username1,username2;username1;username2
321;;;username1
I wish to create a LINQ query which dynamically can add properties for each Role and then fill that property with the correct username(s).
I recognize that the header and the data must be in 2 different statements.
Pseudo code
var result = new { "PropA", Roles.ForEach(x => x.Rolename) }
result += query.Select(x => new { x.PropA, x.UserRoles.ForEach(...) });
Is what I'm trying to do not possible with LINQ and I should do it "manually" with a dynamic object, or is there some black magic I need to learn :)?
Model
public class A
{
public int PropA { get; set; }
public IEnumerable<UserRole> UserRoles { get; set; }
}
public class UserRole
{
public Role Role { get; set; }
public User User { get; set; }
}
public class Role
{
public string Rolename { get; set; }
}
public class User
{
public string Username { get; set; }
}
I ended up doing it "manually" with an ExpandoObject.
foreach (var item in items)
{
var obj = new ExpandoObject() as IDictionary<string, Object>;
obj.Add("PropA", item.PropA);
foreach (var role in roles)
{
obj.Add(role.Name,
String.Join(",", item.UserRole.Where(x => x.Role == role).Select(x => x.User.Name)));
}
// omitted...
}

Joining two lists of different types and sort them by date

I have a first list of entities like this :
public partial class Networking :EntityBase
{
public virtual int NetWorkingId
{
get;
set;
}
public virtual string NetWorkingParam
{
get;
set;
}
public virtual System.DateTime NetWorkingDate
{
get;
set;
}
}
And I have a second list of entities like this:
public partial class PrivateNetwork :EntityBase
{
public virtual int PrivateNetworkId
{
get;
set;
}
public virtual int ContaId
{
get { return _contaId; }
set
{
if (_contaId != value)
{
if (Contact != null && Contact.ContaId != value)
{
Contact = null;
}
_contaId = value;
}
}
}
public virtual Nullable<System.DateTime> DateCreation
{
get;
set;
}
}
I want to collect these two lists in one and sort all the elements by date.
Is that possible ?
You can do this, although it's not very pretty, and you end up with an IEnumerable<object> so you have to check each item's type before you can use it:
IEnumerable<object> sorted = myNetworkingList
.Concat<object>(myPrivateNetworkList)
.OrderBy(n => n is Networking
? (DateTime?)((Networking)n).NetWorkingDate
: ((PrivateNetwork)n).DateCreation);
foreach (object either in sorted)
{
if (either is Networking)
// Networking; do something
else
// PrivateNetwork; do something else
}
This problem could easily be solved by using polymorphism; use a common base class or interface for both classes, which has the DateTime property you want to sort on.
Example:
public abstract class NetworkingBase : EntityBase
{
public DateTime DateToSortOn { get; set; }
}
or
public interface INetworking
{
public DateTime DateToSortOn { get; set; }
}
And then make your classes derive from NetworkingBase or implement INetworking:
public partial class Networking : NetworkingBase
{
...
}
public partial class PrivateNetwork : NetworkingBase
{
...
}
or
public partial class Networking : EntityBase, INetworking
{
...
}
public partial class PrivateNetwork : EntityBase, INetworking
{
...
}
Do a LINQ Union or Concat and then an OrderBy on the resulting collection.
What I should have asked earlier is . . .
What do you want to do after you've sorted them?
The answer to this could have a big impact on the potential solution.
If the answer is something like I need to display a list of the dates, where you only need the dates in order. If so then you don't need to merge the two lists, you can get a sequence of just the ordered dates and use that e.g.
var orderedDates = networks.Select(n => n.NetworkingDate)
.Union(privateNetworks.Select(n => n.DateCreation))
.OrderBy(date => date);
If the answer is I need to display a list of links showing the Date that links to the Id of the object, and something to identify the type of object, then you could get away with something very like the above, with an Anonymous object.
var orderedDates = networks.Select(n => new {Date = n.NetworkingDate, Id = n.NetWorkingId, NetworkType = n.GetType().Name})
.Union(privateNetworks.Select(n => new {Date = n.DateCreation, Id = n.PrivateNetWorkingId, NetworkType = n.GetType().Name}))
.OrderBy(n => n.Date);
However if the answer is I need to send a Shutdown() command to the 10 oldest networks then you really do need a polymorphic solution, where you have a single type that you can call a Shutdown() method on, that will resolve to the specific Shutdown() method on the types you're using.
A Polymorphic solution to use only if user khellang's answer doesn't work for you
From a comment on another answer
#BinaryWorrier I chose this answer because I already have records in
the database, so if I choose to add a new interface how will I deal
with the records already stored before adding the interface ?
I find it difficult to believe that your ORM won't allow you to add an interface to an entity class and not - somehow - mark that interface and/or it's member so they're ignored by the ORM.
However, assuming you can't add a new interface or base class, you can still do this polymorphically.
Add the interface, add a class implementing the interface that for each of your Network classes (the Abstractor classes), then transform the network classes into Abstractor classes, adding them to a List<INetwork> and sorting that list.
public interface INetwork
{
DateTime? Date { get; }
}
public class PrivateNetworkAbstractor
:INetwork
{
private PrivateNetwork network;
public PrivateNetworkAbstractor(PrivateNetwork network)
{
this.network = network;
}
public DateTime? Date
{
get { return network.DateCreation; }
}
}
public class NetworkingAbstractor
: INetwork
{
private Networking networking;
public NetworkingAbstractor(Networking networking)
{
this.networking = networking;
}
public DateTime? Date
{
get { return networking.NetWorkingDate; }
}
}
...
public IEnumerable<INetwork> MergenSort(IEnumerable<Networking> generalNetWorks, IEnumerable<PrivateNetwork> privateNetWorks)
{
return generalNetWorks.Select(n => new NetworkingAbstractor(n)).Cast<INetwork>()
.Union(privateNetWorks.Select(n => new PrivateNetworkAbstractor(n)).Cast<INetwork>())
.OrderBy(n=> n.Date);
}
Create an interface that has the date and implement in in both classes. After that sorting is easy.
public interface INetwork
{
DateTime? Date { get; }
}
public partial class Networking :EntityBase, INetwork
{
public DateTime? Date
{
get { return NetWorkingDate; }
}
}
public partial class PrivateNetwork :EntityBase, INetwork
{
public DateTime? Date
{
get { return DateCreation; }
}
}
var commonList = new List<INetwork>();
// Add instances of PrivateNetwork and Networking to the list
var orderedByDate = commonList.OrderBy(n => n.Date);
First solution is using anonymous type
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example1
{
class Program
{
class Human
{
public string Name { get; set; }
public string Hobby { get; set; }
public DateTime DateOfBirth { get; set; }
}
class Animal
{
public string Name { get; set; }
public string FavouriteFood { get; set; }
public DateTime DateOfBirth { get; set; }
}
static void Main(string[] args)
{
var humans = new List<Human>
{
new Human
{
Name = "Kate",
Hobby = "Fitness",
DateOfBirth = DateTime.Now.AddYears(-27),
},
new Human
{
Name = "John",
Hobby = "Cars",
DateOfBirth = DateTime.Now.AddYears(-32),
},
};
var animals = new List<Animal>
{
new Animal
{
Name = "Fluffy",
FavouriteFood = "Grain",
DateOfBirth = DateTime.Now.AddYears(-2),
},
new Animal
{
Name = "Bongo",
FavouriteFood = "Beef",
DateOfBirth = DateTime.Now.AddYears(-6),
},
};
var customCollection = (from human in humans
select new
{
Name = human.Name,
Date = human.DateOfBirth,
}
).Union(from animal in animals
select new
{
Name = animal.Name,
Date = animal.DateOfBirth,
}).OrderBy(x => x.Date);
foreach (dynamic customItem in customCollection)
Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name));
Console.Read();
}
}
}
or without anonymous type (created CustomClass):
...
class CustomClass
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
...
var customCollection = (from human in humans
select new CustomClass
{
Name = human.Name,
Date = human.DateOfBirth,
}
).Union(from animal in animals
select new CustomClass
{
Name = animal.Name,
Date = animal.DateOfBirth,
}).OrderBy(x => x.Date);
foreach (CustomClass customItem in customCollection)
Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name));
...
I simply added a base class and assigned it as the parent of both list's classes . and then simple did the union . it made the trick

Categories