1

I am stuck with a stack overflow exception in this section of code, it is obviously occurring because the Customer object calls a list of CustomerBackgroundLevel objects, each one of which creates a new customer object. I am trying to find a way around the issue, any help would be appreciated..

Customer Constructor -

public CustomerVO(Customer item)
    {
        CustomerID = item.CustomerID;
        CustomerName = item.CustomerName;
        ECNNumber = item.ECNNumber;

        CustomerBackgroundLevels = item.CustomerBackgroundLevels.Select(c => new CustomerBackgroundLevelVO(c)).ToList();
    }

Customer Background Level Constructor -

        public CustomerBackgroundLevelVO(CustomerBackgroundLevel item)
    {
        CustomerBackgroundLevelID = item.CustomerBackgroundLevelID;
        CustomerID = item.CustomerID;
        BackgroundLevelID = item.BackgroundLevelID;
        StartDate = item.StartDate;
        EndDate = item.EndDate;
        Customer = new CustomerVO(item.Customer);
        BackgroundLevel = new BackgroundLevelVO(item.BackgroundLevel);
    }

Customer Get Method -

        public CustomerVO GetByID(int id)
    {
        var item = repository.AsQueryable().Where(x => x.CustomerID == id).FirstOrDefault();
        if (item == null)
            return null;

        return new CustomerVO(item);
    }
user1948635
  • 1,357
  • 4
  • 15
  • 22
  • As a solution, perhaps add a constructor overload for `CustomerBackgroundLevelVO` that takes a `CustomerVO`. Then you can just directly assign it to `CustomerBackgroundLevelVO.Customer` rather than instantiating a new one. Your Linq call in the `CustomerVO` constructor would then look like: `CustomerBackgroundLevels = item.CustomerBackgroundLevels.Select(c => new CustomerBackgroundLevelVO(c, this)).ToList()` which will avoid the infinite loop. This only makes sense though if you A) want to reuse the same `CustomerVO` object, and B) don't mind passing a not fully initialized object. – Chris Sinclair Mar 26 '13 at 13:13
  • Or better yet, ditch all this wiring/sub-object construction in their constructors and delegate it out to a specific `Factory` or `Builder` object to create/wire these objects _for_ you and avoid all the nested/recursive interdependencies altogether. – Chris Sinclair Mar 26 '13 at 13:14

3 Answers3

2

Yeah, as you've stated creating new objects in a loop like that is gonna lead to nothing good.

Instead of creating all these wrapper objects in your constructors, why don't you wrap them on demand? That is, when you execute some code that needs a CustomerVO object, create the CustomerVO object within that function and then let it go out of scope when the function ends.

j__m
  • 9,392
  • 1
  • 32
  • 56
1

You can solve your loop like this:

public CustomerVO(Customer item)
{
    CustomerID = item.CustomerID;
    CustomerName = item.CustomerName;
    ECNNumber = item.ECNNumber;

    **CustomerBackgroundLevels = item.CustomerBackgroundLevels.Select(c => new CustomerBackgroundLevelVO(c,this)).ToList();
}

**public CustomerBackgroundLevelVO(CustomerBackgroundLevel item, CustomerVO vocustomer)
{
    CustomerBackgroundLevelID = item.CustomerBackgroundLevelID;
    CustomerID = item.CustomerID;
    BackgroundLevelID = item.BackgroundLevelID;
    StartDate = item.StartDate;
    EndDate = item.EndDate;
    **Customer = vocustomer;
    BackgroundLevel = new BackgroundLevelVO(item.BackgroundLevel);
}
Peter
  • 27,590
  • 8
  • 64
  • 84
  • Thanks for this, works very nicely. Probably going to have to re-consider this approach now though, due to the initial load speed :( – user1948635 Mar 26 '13 at 17:04
0

Is that a copy constructor? If so, you need to create a custom constructor for copying the item rather than using it in both scenarios where you new up an object and copy it.

return new CustomerVO(item);

The above is unnecessary and the problem line is:

Customer = new CustomerVO(item.Customer);

Change the above line to this:

Customer = item.Customer;

Unless you are having reference problems, which means you need to design a new constructor.

And if the item.Customer object is not a CustomerVO object, then you will need to pass the reference of the current CustomerVO object into the constructor of the CustomerBackgroundLevelVO.

Caleb Keith
  • 816
  • 4
  • 10