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
Related
I have a question regarding Lists in c# I have a method:
public void example(Employee emp)
Now I need to write
example();
in another method
But when I do it it shows me an error because I need to put something in () but I don't know what or how.
Thanks!
public void SaveToFile(Employee emp)
{
var path2 = Path.Combine(Directory.GetCurrentDirectory(), "text.txt");
File.AppendAllText(path2, emp2 + Environment.NewLine);
}
//ABOVE ME IS THE METHOD I WANNA CALL
//BELOW IS THE START PROGRAM THING (employeedata is another script)
private static void MainMenu(ref EmployeeData employeeData)
{
employeeData.SaveToFile(Employee emp);
}
After all the comments, I guess this is what you need: You must pass one employee object in parameters when calling your void.
Employeee emp = new Employee();
emp.propertyOne = "stuff";
emp.propertyTwo = "more stuff";
example(emp);
You need to pass in a value between the () which are called parameters, because in your method you are asking for an object with the type of Employee. Please check the following url where you can learn more about parameters:
Parameters in C#
What you are missing is a way to convert your Employee object into a string for writing into a file. Use the .ToString() override to do so.
public class Employee
{
public Employee()
{
// Constructor defaults
ID = 0;
Name = string.Empty;
}
public bool IsValid
{
get
{
// Check if ID and Name are set
return ID > 0 && !string.IsNullOrWhiteSpace(Name);
}
}
public int ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
// String representation of an Employee
return $"{ID}, {Name}";
}
}
Then you can have code that reads and writes to files
public static class EmployeeData
{
public static void AppendToFile(string filename, Employee employee)
{
// Use `ToString()` to convert `Employee` to `string`
File.AppendAllText(filename, employee.ToString() + Environment.NewLine);
}
public static Employee Parse(string description)
{
// Take a string of the form "100, John" and split it
// into parts at the comma
string[] parts = description.Trim().Split(',');
Employee emp = new Employee();
if (parts.Length > 0 && int.TryParse(parts[0].Trim(), out int id))
{
// If first part is an integer, assign it to the ID
emp.ID = id;
}
if (parts.Length > 1)
{
// Assign second part to name
emp.Name = parts[1];
}
return emp;
}
public static List<Employee> ReadFromFile(string filename)
{
// Read all text from file as separate lines
List<Employee> list = new List<Employee>();
string[] lines = File.ReadAllLines(filename, Encoding.UTF8);
foreach (var line in lines)
{
// Convert each line of text into an Employee object
Employee emp = Parse(line);
if (emp.IsValid)
{
// If the object is valid add to the list
list.Add(emp);
}
}
return list;
}
}
and the above is used in the following proof of concept code below:
internal class Program
{
static void Main(string[] args)
{
Employee emp1 = new Employee()
{
ID = 1,
Name = "Peter",
};
EmployeeData.AppendToFile("test.txt", emp1);
Employee emp2 = new Employee()
{
ID = 2,
Name = "Maria",
};
EmployeeData.AppendToFile("test.txt", emp2);
List<Employee> employees = EmployeeData.ReadFromFile("test.txt");
foreach (var item in employees)
{
Console.WriteLine(item);
// This calls item.ToString()
}
}
}
which prints the following on the console window the first time its run
1, Peter
2, Maria
Note that each time the program runs it adds to the above creating duplicates. That is a subject of a different question, on how to write an .Equals() function to check for duplicates.
I have seen a number of answers for this problem but can't find that how can i resolve the issue I'm facing.
I had the following code vb
Public Shared Function GetOtherDomains() As List(Of DomainModel)
Dim list As New List(Of DomainModel)
Dim items As List(Of Object) = BusinessFactory.tblDomain.GetOtherDomains(Sessions.LoginID)
For Each item As Object In items
Dim model As New DomainModel()
With model
.LoginID = item.LoginID
.DomainID = item.CompanyID
.CompanyName = item.CompanyName
.RoleName = item.RoleName
End With
list.Add(model)
Next
Return list
End Function
I converted the code in c# as below and now getting the error('object' does not contain a definition for 'LoginID')
public static List<DomainModel> GetOtherDomains()
{
List<DomainModel> list = new List<DomainModel>();
List<dynamic> items = BusinessFactory.tblDomain.GetOtherDomains(Sessions.LoginID);
foreach (dynamic item in items)
{
DomainModel model = new DomainModel();
model.LoginID = item.LoginID;
model.DomainID = item.CompanyID;
model.CompanyName = item.CompanyName;
model.RoleName = item.RoleName;
list.Add(model);
}
return list;
}
Please let me know that how it can be resolved?
Is there any specific reason for using dynamic keyword? dynamic keyword is checked at runtime so if there is any compile time error it will skip it. Try using below code:-
public static List<DomainModel> GetOtherDomains()
{
List<DomainModel> list = new List<DomainModel>();
List<object> items = BusinessFactory.tblDomain.GetOtherDomains(Sessions.LoginID);
foreach (object item in items)
{
DomainModel model = new DomainModel();
model.LoginID = item.LoginID;
model.DomainID = item.CompanyID;
model.CompanyName = item.CompanyName;
model.RoleName = item.RoleName;
list.Add(model);
}
return list;
}
It is not simply a case of casting your List<dynamic> as you will get an
Unable to cast object of type 'System.Dynamic.ExpandoObject' to type 'DomainModel' error.
If your BusinessFactory returns List<dynamic> items you could take the following approach.
Simply use the JavaScriptSerializer to convert the List<dynamic> into a List<DomainModel>.
This would eleviate even the need to loop or do anything in your method becoming:
public static List<DomainModel> GetOtherDomains()
{
List<dynamic> list = BusinessFactory.tblDomain.GetOtherDomains(Sessions.LoginID);
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<DomainModel> domainList =
jsSerializer.ConvertToType<List<DomainModel>>(list);
return domainList;
}
Here is a simple test setup to prove this works:
void Main()
{
var list = GetDynamicObjects();
// Linqpad output
list.Dump();
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<DomainModel> domainList = jsSerializer.ConvertToType<List<DomainModel>>(list);
domainList.Dump();
}
private List<dynamic> GetDynamicObjects()
{
List<dynamic> list = new List<dynamic>();
list.Add(GetDynamicObject(1));
list.Add(GetDynamicObject(2));
return list;
}
private dynamic GetDynamicObject(int id)
{
dynamic dyno = new System.Dynamic.ExpandoObject();
dyno.LoginID = "LoginID" + id;
dyno.DomainID = "DomainID"+ id;
dyno.CompanyName = "CompanyName"+ id;
dyno.RoleName = "RoleName"+ id;
return dyno;
}
public class DomainModel
{
public string LoginID { get;set; }
public string DomainID { get;set; }
public string CompanyName { get;set; }
public string RoleName { get;set; }
}
Output
I have letter and user tables in database:
User("Id", "Name")
Letter("Id", "UserId", "Title")
and i use this code in class for get letter list:
public static mytype GetList()
{
var lst = (from l in Letters.ToList()
select new {l.Id, l.Title, l.tblUsers.Name}).ToList();
return lst;
}
please help me for choosing the right type. i want not use this code:
public static List<Letter> GetList()
{
List<Letter> lst = new List<Letter>();
lst = (from l in Letters.ToList()
select l).ToList();
return lst;
}
You need to define a type for this.
new {l.Id, l.Title, l.tblUsers.Name}
is the definition of an anonymous class. To use it as a return value, you should define a struct or class which represents the information you want to return. You can use dynamic, but it will easily lead to runtime errors when you change the returned data structure as the callers of the method will not know how the return value looks like.
For example:
struct UserLetter {
public Guid Id {get;set;}
public string Title {get;set;}
public string AuthorName {get;set;}
}
public static IList<UserLetter> GetList()
{
return (from l in Letters
select new UserLetter
{ Id = l.Id, Title = l.Title, AuthorName = l.tblUsers.Name}).ToList();
}
Try like this
class mytype
{
public int id;
public string title;
public string name;
}
public static List<mytype> GetList()
{
return (from l in Letters.ToList() select new mytype{id=l.Id,title=l.Title, name=l.tblUsers.Name}).ToList();
}
You need to apply a join with user table.
public static List<objLetter> GetList()
{
List<objLetter> lst = new List<objLetter>();
lst = from ltr in Letters
join user in Users on ltr.UserId equals user.UserId
select new objLetter {Id = ltr.Id , Title = ltr.Title, Name = user.Name })
return lst;
}
You're creating an anonymous type so either you can create a new class holding the properties you're interested in or use dynamic objects
public static IEnumerable<dynamic> GetList()
{
var lst = (from l in Letters.ToList()
select new {Id = l.Id, Title = l.Title, UserName = l.tblUsers.Name}).ToList();
return lst;
}
Then in your calling code just iterate over the dynamics objects and call the dynamic properties
foreach (var dynamicObject in GetList())
{
Console.WriteLine(dynamicObject.UserName);
}
Unless your dynamic objects have a very small scope in your application, a new class would probably be a better choice since you'll benefit from type-checks
I want to select columns dynamically from List as following. So what could be the best way?
//a objects list
List<DashBoard> dashboardlist = (List<DashBoard>)objList;
string strColumns = "RecDate,ModifiedDate";
objList = (from obj in dashboardlist select new { strColumns }).ToList();
/////////////
Ok,Just forget Object List say I have database table which have number of column ID,Name,Age,sex,etc ..Then I have columnList to display and the columnList is change according to condition . SO I have List people; and List columnTemplate; so now I want to select the column based on the template .
Thanks for providing ideas to my question.Spending couple of hours in
Google I found solution .
public void Test() {
var data = new[] {
new TestData { X = 1, Y = 2, Z = 3 }
, new TestData { X = 2, Y = 4, Z = 6 }
};
var strColumns = "X,Z".Split(',');
foreach (var item in data.Select(a => Projection(a, strColumns))) {
Console.WriteLine("{0} {1}", item.X, item.Z);
}
}
private static dynamic Projection(object a, IEnumerable<string> props) {
if (a == null) {
return null;
}
IDictionary<string,object> res = new ExpandoObject();
var type = a.GetType();
foreach (var pair in props.Select(n => new {
Name = n
, Property = type.GetProperty(n)})) {
res[pair.Name] = pair.Property.GetValue(a, new object[0]);
}
return res;
}
class TestData {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
I assume that the list of the columns may come from an external resource and change, I propose:
With reflection you could produce a list of FieldInfo that correspond to each Column, then loop over each item on the list and each FieldInfo and call GetValue on the data object.
Here is the solution:
Select a Column Dynamically using LINQ?
and look Dynamic Linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Let's supposed that you have only 2 templates. You can create a method for each template, that returns only the columns you need. Something like this:
// method for template 1 - returns only 3 columns/properties
private DashBoard CreateDashBoardXxxxxxx(DashBoard item)
{
return new DashBoard {
Property1 = item.Property1,
Property4 = item.Property2,
Property3 = item.Property3
};
}
// method for template 2 - returns N columns/properties
private DashBoard CreateDashBoardYyyyyyyy(DashBoard item)
{
return new DashBoard {
Property1 = item.Property1,
Property4 = item.Property2,
// Other properties
// .....
PropertyN = item.PropertyN
};
}
You can then use those methods like this:
List<DashBoard> dashboardlist = (List<DashBoard>)objList;
// using template 1
var list = dashboardlist.Select(CreateDashBoardXxxxxxx);
// using template 2
var list2 = dashboardlist.Select(CreateDashBoardYyyyyyyy);
You just need to do some code to decide which template should be used.
I hope this helps!!
I have a method called get Data which executes my SQL and returns some rows of ContactLists containing Aggregated Labels.At the moment this method is in my code behind and would like to move it to a separate Data Access class. I would appreciate your assistance. Thanks!
Is normal, if i understand your code, you do this operation after ContactList initialization:
contactList.Labels = new ObservableCollection<Label>()
{
new Label() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
For each ContactList is always added one item, you will do something like this:
contactList.Labels = new ObservableCollection<Label>();
foreach(var item in <yourLabelDataSource>)
contactList.Labels.Add(new Label(...));
The solution is like this:
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
contactList.Labels = new ObservableCollection<Label>()
{
new Label()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
//Add new label because CONTACT_LIST_ID Exists
ContactList contactList = myContactDictionary[id];
contactList.Labels.Add(
new Label()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
Ben, for your last question you can use this solution:
else
{
//Add new label because CONTACT_LIST_ID Exists
ContactList contactList = myContactDictionary[id];
string name = dr["LABEL_NAME"].ToString();
var label = contactList.Labels.Where(l => l.Name == name).FirstOrDefault();
if( label != null )
label.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
else
{
contactList.Labels.Add(
new Label()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
I hope this code is readable and helpfulL!
}
This is other response:
Create and Object Model that can contain your required data:
public class DataResult
{
public ObservableCollection<AggregatedLabel> AggregatedLabels { get; set; }
public ObservableCollection<ContactList> ContactLists { get; set; }
}
You can build a method that return DataResult object, in your method (GetData()), you can valorize the two different properties (AggregatedLabels and ContactsList) with your DB Result. In the and you can return DataResult Object.
A little example here:
public DataResult GetData()
{
DataResult result = new DataResult();
result.AggregatedLabels = new ObservableCollection<AggregatedLabel>();
result.ContactLists = new ObservableCollection<ContactList>();
// Manipulate data result with your method logic like in this examle:
foreach(var something in dbResult)
{
ContactList cl = new ContactList() {
//Binding from something
}
result.ContactLists.Add(cl);
}
return result; //return your Object Model with required Data!
}
I hope it is conceptually clear