Performance of String literals vs constants for Se

2019-02-20 19:42发布

问题:

Session[Constant] vs Session["String Literal"] Performance

I'm retrieving user-specific data like ViewData["CartItems"] = Session["CartItems"]; with a string literal for keys on every request. Should I be using constants for this?

If yes, how should I go about implementing frequently used string literals and will it significantly affect performance on a high-traffic site?


Related question does not address ASP.NET MVC or Session.

回答1:

The reason to use constants has to do with maintainability, not performance. Performance is about the same either way.

With a string literal, you can never tell whether it's the same as another string literal intentionally or by coincidence, so when it's time to change one, you don't know which other ones to change. But if you have the values in constants, you just make the change in one place.

Bad:

ViewData["username"] = Session["username"];

Good:

const UserNameSessionKey = "username";
const UserNameViewDataKey = "username";

ViewData[UserNameViewDataKey] = Session[UserNameSessionkey];

Now imagine changing the value of the session key to "userName" without wanting to change it for any viewdata key...



回答2:

Use the constant because the compiler will give you an error if you mistype it, whereas mistyped strings will just give you wonky bugs.

The performance difference will likely be so small it would be very difficult to measure.



回答3:

Lets go further with maintainability. I'll quote my other answer about using Session:

Lets say we want to store shopping cart is Session of our ASP.NET MVC application. It will be stored in Session["ShoppingCart"], but we want easy, strongly typed access and high testability:

First we define interface:

public interface ISessionWrapper
{
    List<CartItem> ShoppingCart { get; set; }
}

Then we make HttpContext implementation:

public class HttpContextSessionWrapper : ISessionWrapper
{
    private T GetFromSession<T>(string key)
    {
        return (T) HttpContext.Current.Session[key];
    }

    private void SetInSession(string key, object value)
    {
        HttpContext.Current.Session[key] = value;
    }

    public List<CartItem> ShoppingCart
    {
        get { return GetFromSession<List<CartItem>>("ShoppingCart"); }
        set { SetInSession("ShoppingCart", value); }
    }
}

GetFromSession and SetInSession are helper method that make taking and setting data in Session easier. They can be easily reused to access other fields in Session.

Then we define our base controller (applicable to ASP.NET MVC):

public class BaseController : Controller
{
    public ISessionWrapper SessionWrapper { get; set; }

    public BaseController()
    {
        SessionWrapper = new HttpContextSessionWrapper();
    }
}

If you want to use Session outside controller, you just create or inject new HttpContextSessionWrapper().

You can replace SessionWrapper with ISessionWrapper mock in Controller tests, so it is not dependent on HttpContext anymore. Session is also more easy to use, because instead of calling (List<CartItem>)Session["ShoppingCart"], you call SessionWrapper.ShoppingCart. It looks nicer, isn't it?

If you don't use model class for view and I think using model class is better, you can do the same with ViewData:

public interface IViewDataWrapper
{
    List<CartItem> ShoppingCart { get; set; }
}

public class ViewDataWrapper : IViewDataWrapper
{
}

public class BaseController : Controller
{
    public IViewDataWrapper ViewDataWrapper { get; set; }

    public BaseController()
    {
        IViewDataWrapper = new ViewDataWrapper();
    }
}

And then simply in controller:

ViewDataWrapper.ShoppingCart = SessionWrapper.ShoppingCart 

or if you decide not to use ViewData and specific model:

Model.ShoppingCart = SessionWrapper.ShoppingCart

And simply in view (if you define base class for view and introduce this interface):

<%= ViewDataWrapper.ShoppingCart %>

or

<%= Model.ShoppingCart %>

No mistyped strings, strongly typed, nice looking.



回答4:

Just a quick note but a lot of the better examples have a class of SessionKeys containing string constants. This also aids Unit Testing as you can call the constants in your Unit Tests where necessary.

E.g. (just one key but obviously you can add more

public class SessionKeys
{
    public const string UserDto = "UserDto";
}

used as such (I use SessionStateWrapper)

UserDto userDto = _sessionStateWrapper.GetItem(SessionKeys.UserDto) as UserDto;


回答5:

According to this benchmark on the length of dictionary keys, shorter keys are faster. Quoted here:

Dictionary string key length benchmark in C#

Are shorter lookup keys significantly faster? As keys get shorter, lookup time gets faster:

  • Key A - 20 characters: 4436 ms [slowest]
  • Key B - 10 characters: 2010 ms
  • Key C - 5 characters: 1749 ms
  • Key D - 2 characters: 1575 ms [fastest]

where:

  • Key A = "01234567890123456789";
  • Key B = "0123456789";
  • Key C = "01234";
  • Key D = "01";