Apologies if I'm struggling to word this properly. OOP is not my expertise but I'm very much trying to learn.
How do I create an instance of an object on say, every third iteration of a loop?
Within a loop, I need to assign values to an object, but the property to assign a value to will depend on the result of a case statement. Once each property of the object has been assigned, I then need to add that object to a list of objects of the same type.
If I create the object before the loop is entered, then my list just contains the same result over and over again, because (I've read) that the list only contains a reference to the object, and if the object is then changed, so does the list.
If I create the object within the loop, then obviously, I'll get a new object each time with just one of the properties assigned to it by the time it adds it to the list. The list would contain different results, but only the last property would be assigned, as a new object is created each time.
What I assumed you could therefore do was create a new object whenever all of the properties had a value assigned to it (or at the start, when none had). So, since my object has three properties, each time through the loop, I would like to add a new object whenever an int iCounter was 0, add the values, and increment iCounter, then when iCounter is 3, set to 0. However, when I attempt to create an object inside of an if statement, the rest of the program doesn't see the object exists.
I also assumed, I could maybe attempt some kind of macro substitution, which is what I would normally resort to in Fox, however, (I've read) that this is a big no-no in c#.
Any ideas?
try
{
cProducts Product = new cProducts();
SqlConn2.Open();
rdr2 = SqlComm2.ExecuteReader();
int iScanLine = 0;
while (rdr2.Read())
{
iScanLine++;
Product.product = rdr2["product"].ToString();
Product.sOrder = rdr2["order_id"].ToString();
switch (rdr2["detail"].ToString())
{
case "Quantity":
Product.quantity = Convert.ToInt16(rdr2["display_value"]) ;
break;
case "Option":
Product.Option = rdr2["display_value"].ToString();
break;
case "Size":
Product.Size = rdr2["display_value"].ToString();
break;
}
if (iScanLine == 3)
{
lProducts.Add(Product);
thisPage.sProducts.Add(lProducts[lProducts.Count() - 1]);
iScanLine = 0;
}
}
}
You could just change this bit:
if (iScanLine == 3)
{
lProducts.Add(Product);
thisPage.sProducts.Add(Product); //<-- We know the object just added is still in Product
iScanLine = 0;
Product = new cProducts(); //<-- Create a new object to start populating
}
Also, I know that .NET framework is quite new, being only a decade old, but you might consider reading the Naming Guidelines:
X DO NOT use Hungarian notation.
Looks like you have table with four columns, where each product represented in three consecutive rows
product | order_id | detail | display_value
A X Quantity 5
A X Option Foo
A X Size XL
B X Quantity 2
...
And you are trying to read products. I suggest you to store current product name and compare it with last product name. If name is changed, then you are reading data of next product, thus you can create new product and add it to list of products:
IDataReader reader = SqlComm2.ExecuteReader();
List<Product> products = new List<Product>();
Product product = null;
while (reader.Read())
{
var name = reader["product"].ToString();
if (product == null || product.Name != name) // check if new product
{
product = new Product(); // create new product
product.Name = name; // fill name
product.OrderId = reader["order_id"].ToString(); // and order
products.Add(product); // add to products
}
object value = reader["display_value"]; // get value from row
switch (reader["detail"].ToString())
{
case "Quantity":
product.Quantity = Convert.ToInt16(value);
break;
case "Option":
product.Option = value.ToString();
break;
case "Size":
product.Size = value.ToString();
break;
}
}
As you can see, I also refactored naming - PascalCase for properties, camelCase for local variables, no Hungarian notation. Also new names for properties introduced - Product.Name instead of odd Product.Product, OrderId instead of sOrder.
Use the Modulus operator to check whether the iterating variable is divisible by expected nth value or not
if(value % 3 == 0)
{
//do stuff
}
value++;
You are repeatedly adding the same Product to your list, and never create a new one. When you get to the end of your loop, it'll appear as though you've only got a single item in there.
After you've added your item (within the if (iScanLine == 3)), I suspect you want to create a new item: Product = new cProducts().
Also, I would like to reference this particular comment that you make in your question:
If I create the object before the loop is entered, then my list just
contains the same result over and over again, because (I've read) that
the list only contains a reference to the object, and if the object is
then changed, so does the list.
The following code will result in 5 separate objects being added to a list:
List<cProducts> list = new List<cProducts>();
cProducts Product = new cProducts();
for (int i = 0; i < 5; i++)
{
list.Add(Product);
Product = new cProducts();
}
You are correct that the list only contains references to the objects - but you are not changing any of the objects; you are creating new ones. This is a fundamental programming principle, and I'd suggest you take the time to understand how it works before moving on.
Not sure if I understand completely but the following loop whould use a counter to execute every third time
int isThirdTime = 0; //Test condition for third time equality
while (true) //neverending loop
{
if (isThirdTime == 3)//test for 3rd time
{
// add to list
isThirdTime = 0; //reset counter
}
isThirdTime++; // Increase the counter
}
Related
Assume we have an array list of type Employe , does expanding it's length by 1 make a new object in the list ?
is the code in else statement correct? and is it recommended?
public void ModifierEmp(int c)
{
for(int i = 0; i < Ann.Count; i++)
{
if(Ann[i].Code == c)
{
Ann[i].saisie();
} else
{
i = Ann.Count + 1; //expanding arraylist ann
Ann[i].saisie(); //saisie a method for the user to input Employe infos
}
}
}
https://imgur.com/VfFHDKu "code snippet"
i = Ann.Count + 1;
The code above is not expanding the list: it is only setting your index variable (i) to have a new value.
If you wanted to make the list bigger, you would have to tell it which object to put into that new space you create. For example:
Ann.Add(anotherItem);
Of course, this gives you the ability to decide whether to add an existing item, create a new item (e.g. Ann.Add(new Something() { Code = c })), or even add a null value to the list (which is not usually a good idea).
I'm experiencing this behavior. Consider this code
classQtData temp_data = new classData(); //consider this...
public int AddData(ref classSerialPort serial_com )
{
int return_number_of_packet_read;
int index_a;
return_number_of_packet_read = 0;
while (serial_com.GetRawData(ref raw_vector) > 0)
{
//assign temp__data stuffs....
temp_data.rolling_counter = (uint)raw_vector[40];
this.Enqueue(temp_data);
return_number_of_packet_read++;
}
return return_number_of_packet_read;
}
In this case, if while loop is executed (say) 3 times, the same temp_data object (the last inserted) will be enqueued three times, instead of inserting 3 different objects.
This code snippet, otherwise, works as I expect, enqueuing the right elements:
public int AddData(ref classSerialPort serial_com )
{
int return_number_of_packet_read;
int index_a;
return_number_of_packet_read = 0;
while (serial_com.GetRawData(ref raw_vector) > 0)
{
classQtData temp_data = new classData();
//assign temp__data stuffs....
temp_data.rolling_counter = (uint)raw_vector[40];
this.Enqueue(temp_data);
return_number_of_packet_read++;
}
return return_number_of_packet_read;
}
Yes, that is because you have added three identical references to the same object. There is only one classData in your first example, so it should not be surprising that you see the same object multiple times. Basically, the first example is simply wrong, and the second is right: in the second, you create a different object per iteration.
The value of temp_data is simply a reference to an object that lives somewhere else. When you Enqueue(temp_data), you are just adding a copy of the reference to the queue - not a copy of the object. In human terms, that is like copying a street address: it doesn't matter how many copies of that street address you make: they all refer to the single building.
snippets of my code
List<List<optionsSort>> stocks = new List<List<optionsSort>>();
optionsSort tempStock1 = new optionsSort();
List<optionsSort> stock = new List<optionsSort>();
then some code,
for (int j = 1; j < optionsSt.Count; j++)
{
if (optionsSt[j].isin == optionsSt[j - 1].isin)
{
tempStock1.name = optionsSt[j].name;
tempStock1.date = optionsSt[j].date;
tempStock1.strike = optionsSt[j].strike;
tempStock1.size = optionsSt[j].size;
tempStock1.isin = optionsSt[j].isin;
tempStock1.callPut = optionsSt[j].callPut;
stock.Add(tempStock1);
}
else
{
stocks.Add(stock);
k = k + 1;
stock.Clear();
tempStock1.name = optionsSt[j].name;
tempStock1.date = optionsSt[j].date;
tempStock1.strike = optionsSt[j].strike;
tempStock1.size = optionsSt[j].size;
tempStock1.isin = optionsSt[j].isin;
tempStock1.callPut = optionsSt[j].callPut;
stock.Add(tempStock1);
}
}//endfor
Basicly, im going through a large list to sort elements into groups, a new List name stocks.
now the problem is, when I add to stocks all elements contained in the list stock and then clear stock on the next line to start again, I delete all the elements I have stored in stocks.
Any Ideas. Do I have to index stocks like stocks[i].Add(stock) so each block of similar stocks is an element in stocks.
Thanks for any help.
The problem is that List<T> objects, like all classes in .NET, are reference types. That means that every time you add stock to stocks you aren't adding a new list, you are only adding a reference to the same list in memory. So when you later call Clear, that is reflected both in your variable stock and in all other references in stocks.
You can resolve this by making a shallow copy of stock every time you add it to stocks:
stocks.Add(stock.ToList());
You're not creating a new list, you're using one list, and filling it and clearing it repeatedly. Since your outer list contains only one list, repeated multiple times, that list will have the same contents in every instance. That is, when you clear your list, you can no longer access the old contents, even if you try to access them from inside the outer list.
What you need to do is to change this line:
stock.Clear();
To this:
stock = new List<optionsSort>();
That is what you really meant. :)
I have the following Item(s) A (string) and Item(s) B (decimal) In my WPF ListBox. I intend to
to save them to a table in MS SQL database with the respective data type.
DataClasses1DataContext dc = new DataClasses1DataContext();
foreach (var items in MyListBox.Items)
{
//I was thinking in this terms but I doubt if its the correct code
items=MyListBox.Items.Cast<String>().ToList();
//
//Then use this Linq Statement to insert the data
Student std = new Student();
std.Name=items
std.Marks=items
dc.Student.InsertOnSubmit(std);
dc.SubmitChanges();
}
Any clarifications needed please ask, I am still a leaner in C#, wpf, Linq
Ok here's an algorithm to create a list of Students from the contents of your ListBox. There is no error checking here so you'll have to handle that later depending on your needs. I'll give a little explanation at the bottom.
List<Student> students = new List<Student>();
double dub = 0;
items = MyListBox.Items.Cast<String>().ToList();
for (int i = 0; i < items.Length; i++)
{
if (i % 2 == 0)
{
dub = double.Parse(items[i]);
}
else
{
Student s = new Student();
s.Name = items[i];
s.Marks = dub;
students.Add(s);
}
}
Alright so here is how it works. Outside of the loop I allocate a list of students, we'll need that to hold the unknown number students coming from the listbox. I used a for loop rather than a for each so that I can use the mod operator to check whether the value is the double or the string. Doubles should come first so I'm holding that in a temp variable. If it's a double I parse it and assign the result to dub. Because we're dealing with pairs if i % 2 != 0 then the current item is a name, that's why I'm safe using an else block. In the else block I allocate a new student object and set the name with the current item. Then I set the marks with my cached double. At that point I can just add it to the list. Alternatively in the else block you could use a constructor that accepts a double and a string and does the assignment. We'll know both values at that point so that would be a cleaner solution.
Work on Vs2010 EF,C#.
Have two list(oLisTranItem,oListTaxItem) ,need to copy one list properties values in another list ,then I need to work on new list.Problem is after copy content element one list to another list any type of changes impact on both list ,why this happen ,I just change on list but changes occur in both list
Please check my bellow syntax.
List<TransactionItem> oLisTranItem = new List<TransactionItem>();
List<TransactionItem> oListTaxItem = new List<TransactionItem>();
oLisTranItem = _TransactionItem;
oListTaxItem = _TransactionItemTax;
TransactionItem tmpItem = new TransactionItem();
tmpItem = oLisTranItem.Where(item => item.QuotationDetailID == quotationDetailID && item.Action != Entity.ActionMode.Delete && item.IsDeleted == false).FirstOrDefault();
if (tmpItem.IsNotNull())
{
tmpItem.Action = Entity.ActionMode.Add;
oListTaxItem.Add(tmpItem);
}
else
{
_TransactionItemTax = new List<TransactionItem>();
}
int nCounter = 5;
foreach (TransactionItem item in oListTaxItem)
{
if (item.QuotationTaxID ==0)
{
nCounter = nCounter + 1;
item.QuotationTaxID = nCounter;
}
}
Please help me to identify why this problem aries,how to solve this problem.
If have any query please ask,Thanks in advanced.
TransactionItem is probably a class, right? And not a struct.
Every type that's a class is, by default, a reference type. That means what you have in the lists are not the real values of the transaction items, but references (think C++ pointers) to those values. So when you copy data from one list to the other, you're just copying references.
You need to clone the items from one list to another. Give your class a method to clone instances, and use that method to copy items from one list to another.