I'm doing a simple program to add a student(with ID,Name) to a List, then to search Student by ID through session.
Add Student Module is like below,
protected void addStudent(object sender, EventArgs e)
{
List<Student> thisstdlist = new List<Student>();
thisstdlist = (List<Student>)Session["stdlist"];
thisstdlist.Add(new Student(txtsid.Text,txtsname.Text));
Session["stdlist"] = thisstdlist;
Response.Redirect("Home.aspx");
}
Search Student Module is Like Below,
protected void searchStudent(object sender, EventArgs e)
{
foreach (Student element in (List<Student>)Session["stdlist"])
{
if(element.getID().Equals(txtstdid.Text)){
txtstdname.Text = element.getName();
}
}
}
Student Class is like below,
public class Student
{
private String Name;
private String ID;
public Student(String sid, String sn) {
this.Name = sn;
this.ID = sid;
}
public String getName() {
return this.Name;
}
public String getID()
{
return this.ID;
}
}
But when I added students, for ex: 100,John and Search by 100 it gives me no result. Please can anyone show me the mistake or the correct way of doing this.
are you setting breakpoints and actually checking what the values of these lists and what is actually stored in the session?
.Equals() is not doing what you think it is
try :
foreach (Student element in (List<Student>)Session["stdlist"])
{
if(element.ID == txtstdid.Text){
txtstdname.Text = element.getName();
}
}
The add Student module won't initialize the student list correctly - you are creating a new List<Student> and then throwing the new list away with the next line assignment. I would go with something like:
var thisstdlist = (List<Student>)Session["stdlist"];
// If a key isn't found in Session, it will be null ..
if (thisstdlist == null)
{
// i.e. only re-initialize if it was missing from session
thisstdlist = new List<Student>();
// You don't need to continually reassign the session variable
Session["stdlist"] = thisstdlist;
}
// Adds to the list; now that Session also has a reference to the same list
thisstdlist.Add(new Student(txtsid.Text,txtsname.Text));
As per the comment, note that c# has automatic (albeit mutable) properties - you don't need the Java-style getters and setters.
public class Student
{
public Student(string sid, string sn)
{
Name = sn;
ID = sid;
}
public string Name
{
get;
set;
}
public string ID
{
get;
set;
}
}
Also, in .Net, == for strings is overridden to test values (unlike Java's reference equality for strings), so you can rewrite the comparison as:
if (element.ID == txtstdid.Text)
{
txtstdname.Text = element.Name;
}
Re : foreach - I guess means that you are using the List in a Dictionary (HashMap) fashion - if you use Dictionary instead of List - this will allow you do remove the foreach in favour of:
// addStudent ...
var txtstdname = new Dictionary<string, Student>();
// ...
txtstdname.Add(txtsid.Text, new Student(txtsid.Text,txtsname.Text))
// searchStudent ...
Student element = null;
if (txtstdname.TryGetValue(out element))
{
txtstdname.Text = element.Name();
}
Related
I am coding an application for my study, but i'm stuck at this point. I made a class called 'Neighborhood'. This class has a string and an int. In my main code I give the class a value and put it in a list. I now want to loop through my list and get the int out of it (put it in a listbox, or do a calculation). How do I get the int out of the list?
class Wijk
{
private string wijken;
private int tijd;
public string Wijken
{
get { return wijken; }
set { wijken = value; }
}
public int Tijd
{
get { return tijd; }
set { tijd = value; }
}
}
Created the list and the instance of the class.
List<object> Uden = new List<object>();
Wijk Wijkeninput = new Wijk();
Now I value the string and int with a combobox and textbox.
private void wijkAanmaken()
{
Wijkeninput.Wijken = Convert.ToString(cbWijken);
Wijkeninput.Tijd = Convert.ToInt16(tbSnelheid.Text);
Uden.Add(Wijkeninput);
}
For this, instead of having an object list, you can have list containing class objects like
List<Wjik> Uden = new List<Wjik>();
then you can access int as follows:
foreach (Wjik obj in listProgram)
{
int tij = Convert.ToInt32(obj.tijd);
}
First the List can be declared like this:
List<Wijk> Uden = new List<Wijk>();
To iterate over it:
foreach(var item in Uden)
{
var myInt = item.Tijd;
var myString = item.Wijken;
//here do whatever you want with the values
}
There are semi answer to this question which I have read through thoroughly, as well as all things MSDN about generic classes but I am still having trouble when a generic class inherits from another class: where T: ClassName
For example, here is my generic list class
public class MyGenericList2<T> where T : Person
{
private T[] list;
public MyGenericList2(int size)
{
list = new T[size];
}
public T getItem(int index)
{
T temp = default(T);
temp = list[index];
return temp;
}
public void setItem(int index, T value)
{
list[index] = value;
}
public void DisplayList()
{
for (int i = 0; i < list.Length; i++)
{
Console.Out.WriteLine(list[i]);
}
}
}
It inherits from the person class:
NOTE: It is shortened for clarity sake
public abstract class Person
{
protected string firstName;
// Getters
public string getFirstName()
{
return this.firstName;
}
public void setFirstName(string fname)
{
this.firstName = fname;
}
}
When I try to call it I get an error about trying to convert a string to a {namespace}.Person which I sort of get, in that I am trying to put a string into a 'Person' box, but how does one call the class using this mechanism?
Here is the main method
public static void Main(string[] args)
{
MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
Student st1 = new Student();
st1.setFirstName("Thor");
studentGeneric.setItem(0, st1); //This does not work
studentGeneric.setItem(1, Person.setFirstName("Odin"); // Does not work
studentGeneric.setItem(2, st1.setFirstName("Slepnir"); // Does not work
studentGeneric.DisplayList();
Console.ReadLine();
}
If I cut out the Where T : Person and use GenericList2<string> it works fine, which makes sense since it is string to string.
Any help would be appreciated
quick clarification Student inherits from Person:
public class Student : Person
{
// Student 1
private string studentID01 = "001";
public string getStudentID01()
{
return this.studentID01;
}
}
First of all I would recommend using public properties for your classes, for example:
public abstract class Person
{
public string FirstName { get; set; }
}
public class Student : Person
{
public string StudentId { get; set; }
}
This means your list code would work like this:
Student st1 = new Student();
st1.FirstName = "Thor";
studentGeneric.setItem(0, st1);
And you can even use this syntax:
studentGeneric.setItem(1, new Student
{
FirstName = "Odin"
});
Additionally, the .Net Framework already provides a really nice set of generic collection classes you can use so you don't really need your MyGenericList2<T> class. For example, the most commonly used class is System.Collections.Generic.List:
var people = new System.Collections.Generic.List<Person>();
people.Add(new Student
{
FirstName = "Odin"
});
Or even using the collection initialiser syntax:
var people = new System.Collections.Generic.List<Person>
{
new Student
{
FirstName = "Odin"
}
});
Finally, the problem you are having with outputting your values to the console is because C# doesn't know what to do with your class so by default outputs the value of student.ToString(). And becaue you haven't told your class what to do with it, it just outputs the name of the type. You can either override ToString or, much simpler just call the getFirstName() method:
Console.WriteLine(list[i].getFirstName());
You are using setItem incorrectly. This method can be used to set the value of elements in the list array in an instance of MyGenericList2 class.
To use the setFirstName method on an instance of the Student class, first use getItem to return the object instance. For example:
public void Main(string[] args)
{
MyGenericList2<Person> studentGeneric = new MyGenericList2<Person>(3);
Student st1 = new Student();
st1.setFirstName("Thor");
studentGeneric.setItem(0, st1);
Student st2 = new Student();
studentGeneric.setItem(1, st2);
studentGeneric.getItem(1).setFirstName("Odin");
Student st3 = new Student();
studentGeneric.setItem(2, st3);
studentGeneric.getItem(2).setFirstName("Slepnir");
studentGeneric.DisplayList();
Console.ReadLine();
}
To display the list contents correctly, replace your DisplayList() method with:
public void DisplayList()
{
for (int i = 0; i < list.Length; i++)
{
if(list[i] != null){
Console.Out.WriteLine("{0}: {1}", i, list[i].getFirstName());
}
else
{
Console.Out.WriteLine("{0}: [NULL]", i);
}
}
}
I have list of employees where each Employee contains Properties EmpId,EmpName,PathSuffix.PathSuffix column contains the values EmpPart1.lst,EmplPart2.lst,Emp3456.lst,EmpPart3.lst,Emp5667.lst....
So, Now my question is how to eliminate the duplicates in the employees based on pathsuffix column such that my final list contains only the EmpPart1.lst,Emp3456.lst,Emp5667.lst....(ie removing all part files except one).
How to achieve this ?
Input:
List where each file contains FileName & FilePath.Some of the FilePaths end with Part1,Part2,Part3..whereas some doesn't contain any parts.My requirement is take only one part file ie the higheset one(SourcePart3 in below case)
**FileName FilePath**
Test1.doc SourcePart1.lst
Test2.doc SourcePart2.lst
Test3.doc SourcePart3.lst
Test4.doc Event.lst
Test5.doc CallPart1.lst
Test6.doc CallPart2.lst
**Desired Output:**
**FileName FilePath**
Test3.doc SourcePart3.lst
Test4.doc Event.lst
Test6.doc CallPart2.lst
Let's start by creating our own IEqualityComparer<Employee> to compare our entities and determine if they are duplicates or not.
public class EmployeeComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return String.Equals(x.PathSuffix, y.PathSuffix);
}
public int GetHashCode(Employee obj)
{
return obj.PathSuffix.GetHashCode();
}
}
Supposing you have the following list:
List<Employee> employees;
It's as easy as calling IEnumerable(T).Distinct(T)
List<Employee> uniqueEmployees = employees.Distinct(new EmployeeComparer()).ToList();
A general logic flow for solving this would be to first
select first employee, save his path suffix to a variable, sequentially loop through the list removing any other employee's with the same path suffix value. then increment to your next employee, and repeat.
Also, it's usually easier to check for duplicates when inserting employee's into a list, but I'm without your code I'm not sure exactly how you want to be doing this.
I would create a Dictionary<string, Employee>. Loop over the list once, check the dictionary using ContainsKey, if it returns true, move on, if not, call duct.Add(employee.PathSuffix, employee);
Then use dict.Values.ToList()
I would reconsider how you are storing your data. I would put the path data into a List.
Employee Object:
public class Employee
{
public int EmpId { get; set; }
public string EmpName { get; set; }
public List<string> PathSuffix { get; set; }
public Employee(int ID, string Name, string PathCSV)
{
EmpId = ID;
EmpName = Name;
PathSuffix = new List<string>();
foreach (string path in PathCSV.Split(','))
{
if (string.IsNullOrEmpty(path) == false && path.Trim().Length > 0)
{
if (PathSuffix.Exists(x => x.ToLower() == path.Trim().ToLower()) == false)
{
PathSuffix.Add(path.Trim());
}
}
}
}
}
Samples of the Employee Object
protected void Page_Load(object sender, EventArgs e)
{
List<Employee> MyEmployees = new List<Employee>();
MyEmployees.Add(new Employee(1, "User 1", "Path1,Path1,Path2,Path2,Path2,Path3"));
Response.Write("Employee 1 Information:<br />");
WriteEmployeeToScreen(MyEmployees[0]);
}
protected void WriteEmployeeToScreen(Employee ThisEmployee)
{
System.Text.StringBuilder paths = new System.Text.StringBuilder();
Response.Write(string.Format(
"{1} ({0})<br />",
ThisEmployee.EmpId,
HttpUtility.HtmlEncode(ThisEmployee.EmpName)));
foreach (string path in ThisEmployee.PathSuffix)
{
paths.Append(string.Format(", {0}", path));
}
if (paths.Length > 0)
{
Response.Write(string.Format("Paths: {0}", paths.ToString().Substring(2)));
}
}
OUTPUT:
Employee 1 Information:
User 1 (1)
Paths: Path1, Path2, Path3
Edit to save you from reading through this whole post
tldr: an object's fields should not be static unless you want all instances of that object to have the same value for that field
I'm trying to create and populate an ArrayList of Blog objects. I do know the generic way do this:
create ArrayList of Blogs
loop (some condition)
create new Blog
add this Blog to AL
However, when I attempt to do so within the while(datareader.read()) loop, all of the elements in the ArrayList are exactly the same Blog. Specifically, I end up with an ArrayList filled with multiple pointers to the very last Blog object from the database table. Here is my code:
public static ArrayList AllBlogs()
{
SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");
ArrayList allBlogs = new ArrayList();
if (dr.HasRows)
{
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
}
dr.Close();
return allBlogs;
}
As I said before, the result of this is an ArrayList filled with pointers to the very last blog from the Kristina_Blogs table. I imagine the ArrayList allBlogs looks like [b, b, b, ... b] and therefore they ALL get updated when I say b.setTitle() etc. But how can this be the case if I am creating a NEW Blog object at the beginning of each iteration?
Here is some extra info that you don't have to read but it might clear up some confusion about the structure of the problem:
Blog object has id, title, and message fields and their respective getter/setters
Kristina_Blogs is a table representing these blogs with columns for id, title, message
The suggestions say to include a tag for my DB engine but I can't find a tag for it: Microsoft SQL Server Management Studio
This code works perfectly when I use an ArrayList of Strings instead of Blogs
Edit: Including the code from Blog class
public class Blog
{
public App myApp;
public static string Title;
public static string Message;
public static int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public string getTitle() { return Title; }
public void setTitle(string t) { Title = t; }
}
The main problem you have, as I mentioned in comments is your member variables are static, so when you set the value, they change in all instances. you should change your code this way:
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }
}
And fill your list this way, don't forget to add using System.Linq;:
var result = new List<Blog>();
var connection = #"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
//Get data
adapter.Fill(dataTable);
dataTable.Rows.Cast<DataRow>().ToList()
.ForEach(row =>
{
var b = new Blog();
b.Id = row.Field<int>("Id");
b.Title = row.Field<string>("Title");
b.Message = row.Field<string>("Message");
result.Add(b);
});
return result;
Note:
When you create a member static, it is shared between all instances of that calss.
In C# you can use property to get or set values, you don't need to setX or setY, when you get the value of a property, the get code of that property will execute and when you assign a value to a property the set part of it will execute. you can define properties this way:
Property:
private int id;
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
or more simple:
public int Id { get; set; }
All of the fields in your Blog class are static, meaning they're shared between all object instances. You want them to be instance field (meaning not static) so that each object has its own copy of each of those values.
Remove the static attributes from your class:
public class Blog
{
public App myApp;
public String Title;
public String Message;
public int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }
}
When you use static variables, all instances of an object will contain the same values in those variables. By removing the static keyword, you are allowing different instances of the object to hold different values.
Now, every time you create a blog object, that object's Title and Message etc, will contain its own information.
I would make a quick method to prevent null value from throwing error
public static string GetSafeString(SqlDataReader reader, int index)
{
if (!reader.IsDBNull(index))
return reader.GetString(index);
else
return string.Empty;
}
Replace this code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
With This Code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setId(dr.GetInt32(0));
b.setTitle(GetSafeString(dr, 1);
b.setMessage(GetSafeString(dr, 2);
allBlogs.Add(b);
}
Where the number is the index of field in the record and assuming "id" is an integer. Also consider moving creation of "Blog" object outside of loop and just change values.
I have a WizardInfo class which as several TLists as properties, this then populates as the user goes through the wizard on the last screen I query the Tlists and make them into Lists and private fields
I then create Lists of DefaultItems from these lists. This is my own class and as name and Id as its property.
He is some code
public class DefaultItem
{
public int ID {get;set;}
public string Name {get;set;}
}
private List<DefaultItem> _defaultList = null;
_defaultList = new List<DefaultItem>();
defaultValue = PopulateDefaultList(_asmgps, defaultList);
private int PopulateDefaultList(
List<ASGMP> asmgps,
ref List<DefaultItem> defaultList)
{
int isdefault = -1;
foreach (ASGMP asgmp in asgmps)
{
if (asgmp.IsChecked)
{
if (asgmp.IsDefault)
{
isdefault = asgmp.ID;
}
DefaultItem defaultItem = new DefaultItem();
defaultItem.ID = asgmp.ID;
defaultItem.Name = GetMPTName(asgmp.ID);
defaultList.Add(defaultItem);
}
}
return isdefault;
}
private string GetMPTName(int ID)
{
try
{
SGMP sgmp = DataRepository.SGMPProvider.GetByASGMPID(ID)
if (serviceGroupMailPresentation != null)
{
MPT mpt DataRepository.MPTProvider.GetByMPTID(SGMP.MPTID);
if (mailPresentationType != null)
{
return mpt.Name;
}
}
return string.Empty;
}
catch (Exception ex)
{
WindowsEventLog.Write(ex);
throw;
}
}
The problem i am having is when i remove a item from the defaultList it affects asgmp.
I have found the answer. When I get the mpt name I get asgmp from the database this is where Codesmith does a strange thing and connects the usage of the List and the DefaultList. By querying the original List instead of going to the database it now works fine.
It is being removed because List<T> is derived from object, and is a Reference type. Reference types are passed by reference, i.e. when you pass your list, you are passing a pointer to its location in memory. So any changed you make on the copied reference, will also be reflected on the original object.
In order to make a copy you can change this like:
defaultValue = PopulateDefaultList(_asmgps, defaultList);
to this:
defaultValue = PopulateDefaultList(_asmgps.ToList(), defaultList);
This will enumerate the collection as IEnumerable<T> and return is as a list. This will effectivlly create a copy.
erm, instead of PopulateDefaultList why not just do,
var defaultList = asgmps
.Where(asgmp => asgmp.IsChecked)
.Select(asgmp => new
{
IsDefault = asgmp.IsDefault,
Item = new DefaultItem
{
ID = asgmp.ID,
Name = GetMPTName(asgmp.ID)
}
}).ToList();
of course, naming a collection defaultList that contains non-defaults seems counter intuitive.
I found out that this is because of ntiers instead of using the database the to get the ID I should of used the in List of T in