2

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;
        }

    }
}
6
  • 7
    The % (modulus) operator gives the remainder of integer division. Thus, if n % 3 == 0 then n is divisible by 3. Commented Jun 24, 2013 at 12:31
  • 2
    Note that this actually has very little to do with object-oriented programming per se. What you're really asking is "how do I do something every X iterations of a loop"? The fact that the "do something" in this case is "instantiate a new object" is entirely ancillary. Commented Jun 24, 2013 at 12:33
  • 2
    Maybe you want to re-consider the SQL query returning the data to fix your problem in the first place? Looks like you could modify the query to return one single row per item. Commented Jun 24, 2013 at 12:33
  • Agreed with the SQL query - I had thought about that. Commented Jun 24, 2013 at 12:41
  • As for the modulus operator, I might be understanding you wrong, but my problem isn't that I don't know how to do something every nth time (though I like your solution to that) - it's more of a case of how do I create the object every third time - it won't seem to let me do that because the rest of my code will complain that the object doesn't exist. Commented Jun 24, 2013 at 12:43

5 Answers 5

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

0

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++;

Comments

0

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.

1 Comment

Thanks Dan, that makes a lot of sense. Super impressed at the speed of response here!
0

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.