views:

186

answers:

9

Is there any downside to a class like:

class Example1
{
  protected string UserId = (string)Session["user"];
}
//versus

class Example2
{
  protected string UserId;
  public Example2()
  {
      UserId = (string)Session["user"];
  }
}

If I always want to set this value is there any downside to Example1?

UPDATE:
Session["user"] is set in the Global.asax Session_Start. So if this fails. Nothing should work anyways.

+2  A: 

The main downside is that you can only set the value using a single statement. If, for example, you wanted to check the Session key existed and if it didn't, you wanted to assign it a value, then you couldn't do it by setting the initial value.

lomaxx
+5  A: 

Your biggest problem is if this protected string UserId = (string)Session["user"]; fails. You have no recourse to degrade gracefully. By putting it in the constructor etc. You can check the Session and make a decision on what to do.

As a general rule, I only try and put values that I know are going to succeed like UserId = -1; etc. and then modify them in a code block when I need to. You never know when something is going to go wrong and you need to recover from it.

Kevin
+2  A: 

If you check in the debugger, the setting of the value in the declaration (Example 1) happens before the constructor is called, so you need to make sure that it doesn't rely on anything set up from the constructor.

ChrisF
Good point. I'll remember to check for these situations +1
tyndall
+1  A: 

I'd strongly recommend using a "safe" cast.

UserId = Session["user"] as string;

This way, if the session item doesn't exist, or isn't a string, you don't fail. You simply get a null, which you can test for before using UserId.

Cylon Cat
Safe casting is used way too much in situations like this. If it's not a string, I would imagine that you would probably want an error. You're writing the code in the firsat place, and you are expecting a string, so if it's not a string, it should be raised as a problem that needs to be fixed. I've seen far too many systems demonstrate weird behavior because the wrong type was stored somewhere, and safe cast hide the true error and made it look like an uninitialized variable error instead. Just my two cents.
Mike Mooney
His comment (added after your answer) makes a point that `Session["user"]` *must* be a string, so an exception would be best to nip an issue in the bud
STW
Raising an exception should always be a choice, whenever you know that an exception is possible. Maybe it's right to let the exception fly in this case, but also, maybe not. Safe casting gives you a choice.
Cylon Cat
I almost exclusively use unsafe casts. That way, without any additional checks, I get a fail-fast behaviour, the code breaks where it should, and not three classed and two methods down the line.
SWeko
@SWeko, that may be the behavior that you want, but it probably isn't the behavior the user wants. I would rather handle errors gracefully, and recover non-disruptively.
Cylon Cat
@Cylon - If any of my code is putting non-strings into a session variable that's supposed to have a string in it, I'd rather know about it before I send that crappy code to the user, rather than try to track down the mysterious reason some session variable seems to be null. The user doesn't want that kind of error either, and that kind is harder to debug.
Joel Mueller
@Cylon Users tend to like code that has fewer bugs, instead of code that shows nice error messages now and then :) Using fail-fast, and a top-level exception handler / logger, you can easily detect and fix most critical issues. Exceptions should be, well, exceptional.
SWeko
+1  A: 

AFAIK, there is no real difference between inline value initializers and constructor initialization, except in the order of execution of the statements, and the fact that you are very much restricted to single-line statements in the inline code.

The order of execution is that the value initializers are executed before any constructor logic, in a non-specific order, so if any of the initialization statements happen to have side-effects, you might be in for some nasty surprises. However, it is guaranteed that that code will run, so there is not a possibility of adding an additional constructor later, and forgetting to initialize some field.

I prefer using (chained) constructors to inline initialization, because I find the code to be more readable that way, and also i can do any additional checks that might become necessary down the road.

SWeko
A: 

The guideline that I use: Use field initializers for basic / values known at compile time. If you're doing something like looking up a global collection or some non-trivial logic, move it into the ctor (for error handling/recovery as others have pointed out).

Assuming that you're sure that there would be no errors, the

  • upside: field initializers are easy to read.
  • downside: if you have a bunch of field initializers and multiple ctors, the IL for the initializers would be inserted at the top of each ctor leading to some IL bloat. So in this case, calling an Initialize like method would be better.

Other than that I don't see any downside to field initializers.

Gishu
A: 

It's hard to know to how to begin to say that's not a good idea for many reason. First Session must be a global variable, otherwise your code won't even compile. I am guessing Session in your context here is the System.Web.HttpContext.Current.Session, so, your code won't even compile. Assume you have Session as a global variable, then you must properly initialize it and assign Session["user"], so how are you going to do it? Then you create this dependency between your class and the session, so how do you unit test? Plus all other reasons from all other answers.

Khnle
A: 

You might someday want a second constructor with a different value of UserId.

SeaDrive
A: 

AFAIK the constructor is always called after all fields are initialized. So in Example 2, you're first initializing the field to Null and then to (string)Session["user"].

Markus