tags:

views:

307

answers:

10

This is causing a StackOverFlow error and I have an idea why, but I would like a little more detail on why and is my solution for it the way it should be handled. Ok, first things first, the following code causes a StackOverFlow error when I try to assign a value to the property:

private List<Albums> albums
{
    get
    {
        if (Session["albums"] != null)
            return (List<Albums>)Session["albums"];
        else
            return AlbumCollection.GetAlbums();
    }
    set
    {
    albums = value;
    Session["albums"] = albums;
    }
}

To resolve the above, I changed the name of the property and added another variable to hold the value of the property which resolved the StackOverFlow issue:

private List<Albums> albums = null;
private List<Albums> Albums
{
    get
    {
        if (Session["albums"] != null)
            return (List<Albums>)Session["albums"];
        else
            return AlbumCollection.GetAlbums();
    }
    set
    {
    albums = value;
    Session["albums"] = albums;
    }
}

Also, am I doing the setter correct, assigning the value and then assigning the Session["albums"] the value in albums? Could I have just done, Session["albums"] = value instead?

+10  A: 

You were reassigning to the property itself.

In your case, you are only using the Session.

So this should be fine

private List<Albums> albums
{
    get
    {
     if (Session["albums"] == null)
      Session["albums"] = AlbumCollection.GetAlbums();
     return (List<Albums>)Session["albums"];
    }
    set
    {
     Session["albums"] = value;
    }
}
astander
ok, I was thinking I could do that, but I was afraid I would do it wrong if I didn't do albums = value first. Thanks.
Xaisoft
+5  A: 

The problem is with this line:

albums = value;

You are recursively setting the property to value which will call the setter again and again, until it stackoverflows. There's no point in that line of code. Just get rid of it.

I guess there's a false misconception that a property needs to be bound to a field or something. It's not. A property, by itself, is just a couple unrelated methods, that are not required to have any specific relation to each other or to a field. When you retrieve the property value, you just call its get method and use the return value and when you set its value, you call its set method with the appropriate value argument. You don't need to somehow "change" the property value in setter. The semantics are automatically enforced as you are changing the value that get is going to return so the next time you call get, it will return Session["..."] which you have already changed.

Mehrdad Afshari
+1  A: 

Your setter is calling itself recursively in the first example. Your second fixes this.

Yes, you could have done.

David M
+16  A: 

Because in your setter, you are calling ... the setter, which goes to the setter, and calls ... the setter ... and ...

 set
 {    
    albums = value;       // < --- This line calls itself again.. 
    Session["albums"] = albums;
 }

What you need to do is just use the the Session["albums"] as the persistent storage for the value... You don't need a private field - that's just creating a redundant copy of the value. Eliminate it entirely, and just put...

private List<Albums> Albums
{    
    get    
    {        
         if (Session["albums"] != null)
              return (List<Albums>) Session["albums"];        
         else            
            return (Session["albums"] = AlbumCollection.GetAlbums());    
    }    
    set    
    {    
        Session["albums"] = value;    
    }
}

In certain scenarios where you do not have a persistent store, it's perfectly acceptable for a public property to have just a private member backing field.

For more info on C# properties in general, check out the MSDN tutorial.

Charles Bretana
So, if I just had Session["albums"] = value, it would be fine?
Xaisoft
See my second example...
Charles Bretana
@Xaisoft: Yes, it's all you need.
John Rudy
@Xaisoft: that's one way of doing it; However, if the Albums property is accessed a couple times during the page processing it's much better to cache the deserialized results into a private member.
Chris Lively
Ok, a little confused, should I do Session["albums"] = value or Session["albums"] = albums or is it the same.
Xaisoft
@Chris, are you referring to the way I am actually doing it by declaring the private variable albums in my second attempt? This also brings up another question, how does creating another variable cache the results? I am not to clear on this?
Xaisoft
@tanascius, Thx, correctted...
Charles Bretana
Charles - I've added a few lines, hope you don't mind.
Wim Hollebrandse
@Wim, not at all, But I don;t see them.. Perhaps I was editing at the same time and overwrote yr changes ? If so, please add again...
Charles Bretana
Yes - indeed, a case of 'last-write-wins' concurrency in action. ;-)
Wim Hollebrandse
@Xaisoft, Definitely need "Session["albums"] = value" the other was my bad for copy paste from yr code...
Charles Bretana
Charles, you said I don't need the private field because it is redundant, but what about the comment that Chris Lively made about if I have a private field, it will cache the results.
Xaisoft
He's talking about the difference in read performance accssing a session variable vs. accessing a variable in a method's stack frame. It used to be (some time ago - old classic ASP) that variables or data stored in Session state were substantially more difficult and/or prone to errors than other variables. I don;t believe this is stil the case with ASP.Net, but I'm not sure.
Charles Bretana
Ah ok, so by using a private variable to hold the results of the property, I am accessing the the variable from the stack, but if I don't use a private variable, I am accessing it directly from the session which in the past, was possibly slower, do I have that correct?
Xaisoft
Yes, and, again, as I mentioned, Generally, with standard ASP.Net session, I don't believe there is any real performance issue with in ASP.Net. As I recall, it might be a bit slower if you elect to store session in a database, or on a shared server, (which you might do if your Web Server is in a farm and you wish to share session state among all the members in the farm)
Charles Bretana
+3  A: 

This line is causing your issue, because it winds up calling your getter recursively in an infinite loop:

albums = value;
Justin Niessner
A: 

I do not know the answer about this question but you are obviously on the right website !

BlueTrin
+1  A: 

You are correct, in the first example you are recursively calling the album setter infinite times, hence the stack overflow. (C# Properties and methods should always start with an uppercase letter btw).

In the second example you could simply use:

Session["albums"] = value;

if you wanted to.

Paolo
+1  A: 

You are correct, the issue is when ever you use "albums" in the first code block you are referring to this setter/getter. Thus when you do albums = value in the setter you are recursively calling the setter again.

Internally, the compiler converts accessors to functions, and it may help you to see your error by doing this yourself:

private List<Albums> albums
{
    set
    {
    albums = value;
    Session["albums"] = albums;
    }
}

When compiled, becomes:

private void set_albums(List<Albums> value)
{
    set_albums(value);
    Session["albums"] = albums;
}
SoapBox
+3  A: 

After some brisk searching, this should help you out: http://stackoverflow.com/questions/1929141/why-does-this-cause-a-stackoverflow-error

zincorp
lol, this is a link back to my this question.
Xaisoft
A: 

It's a common mistake to call Session["Albums"] twice. Session indexing is a relatively expensive operation involving a dictionary lookup.

private List<Albums> Albums {    
get
{        
     object stored = Session["albums"];
     if (stored != null)
          return (List<Albums>) stored;
     else
     {      
        var newValue = AlbumCollection.GetAlbums();
        Albums = newValue;
        return newValue;
     }
}    
set    
{    
    Session["albums"] = value;
}}
George Polevoy
I see what you are saying, instead of accessing session in the if statement and when I return the List of albums, store it in an object first and check the object? Correct?
Xaisoft