C# 会话[…]字典键的字符串文字与常量的性能 会话[常量]与会话[“字符串文字”]性能

C# 会话[…]字典键的字符串文字与常量的性能 会话[常量]与会话[“字符串文字”]性能,c#,asp.net-mvc,session,dictionary,string-literals,C#,Asp.net Mvc,Session,Dictionary,String Literals,我正在检索特定于用户的数据,比如ViewData[“CartItems”]=Session[“CartItems”]

我正在检索特定于用户的数据,比如
ViewData[“CartItems”]=Session[“CartItems”]
如果是,我应该如何实现经常使用的字符串文本,以及它是否会显著影响高流量站点的性能



不处理ASP.NET MVC或
会话

使用常量,因为如果您键入错误,编译器将给您一个错误,而键入错误的字符串只会给您带来不可靠的错误


性能差异可能非常小,很难测量。

使用常数的原因与可维护性有关,而不是性能。无论哪种方式,性能都差不多

对于一个字符串文字,您永远无法判断它是故意还是巧合地与另一个字符串文字相同,因此,当需要更改一个字符串文字时,您不知道要更改哪些其他字符串文字。但是如果你有常量中的值,你只需要在一个地方进行更改

坏的:

好:


现在想象一下,将会话键的值更改为“userName”,而不想更改任何viewdata键的值…

让我们进一步讨论可维护性。我将引用关于使用会话的其他答案:

假设我们要存储购物车是ASP.NET MVC应用程序的会话。它将存储在
会话[“ShoppingCart”]
中,但我们需要简单、强类型的访问和高测试性:

首先,我们定义接口:

public interface ISessionWrapper
{
    List<CartItem> ShoppingCart { get; set; }
}
<%= ViewDataWrapper.ShoppingCart %>
若要在控制器外部使用会话,只需创建或注入新的HttpContextSessionWrapper()

您可以在控制器测试中用ISessionWrapper mock替换SessionWrapper,这样它就不再依赖于HttpContext了。会话也更易于使用,因为您不需要调用
(List)会话[“ShoppingCart”]
,而是调用
SessionWrapper.ShoppingCart
。看起来好多了,不是吗

如果不使用模型类进行查看,并且我认为使用模型类更好,则可以对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();
    }
}
或者,如果您决定不使用ViewData和特定模型:

Model.ShoppingCart=SessionWrapper.ShoppingCart

在视图中(如果您为视图定义基类并引入此接口):




没有输入错误的字符串,强类型,美观。

只是一个简短的说明,但许多更好的示例都有一类包含字符串常量的会话键。这也有助于单元测试,因为您可以在必要时调用单元测试中的常量

例如(只有一个键,但显然你可以添加更多。)

public class SessionKeys
{
    public const string UserDto = "UserDto";
}
这样使用(我使用SessionStateWrapper)

根据字典键的长度,键越短速度越快。此处引用:

C语言中字典字符串键长基准测试# 较短的查找键是否明显更快?随着键变短,查找时间也会变快:

  • 键A-20个字符:4436毫秒[最慢]
  • 键B-10个字符:2010毫秒
  • 键C-5个字符:1749毫秒
  • 键D-2个字符:1575毫秒[最快]
其中:

  • 键A=“01234567890123456789”
  • 键B=“0123456789”
  • 键C=“01234”
  • 键D=“01”

您过早地进行了优化。如果您评测应用程序并测量会话访问,那么总请求时间的哪一部分会更小?0.1%?0.01%?当您进行了测量并知道瓶颈是什么时,您应该进行优化。同时,更加关注可读性和可维护性。设计良好的程序易于优化。优化良好程序很难重新设计。此代码肯定不新鲜:)@queen3:优化前的问题。没有瓶颈,只是研究最佳实践。实际上,性能差异不会很小,它是不存在的:编译器用常量的值替换常量,因此最终得到完全相同的结果IL@ScottS:很好,简洁的回答,但Sudit以可维护性和会话键与ViewData键之间的断开连接为重点,并以一个例子说明了这一点。@Thomas:我不知道C#在代码字符串中用常量替换。很高兴知道。@Fresh:因为C#字符串是不可变的,所以它通常在内存中组合相同的文本。您可能还想查找与此相关的字符串实习@Thomas L,我把性能差异留了一点模糊,因为我不确定字符串的插入会有多完美。由于额外的可执行文件大小或字符串的不同内存位置,可能会有微小的差异。非常小的差异,如果有的话。很好。为什么不更进一步,让const UserNameKey=“username”;这样,您就可以自由区分两个键或保持它们相同。即:const UserNameSessionKey=UserNameKey;和const UserNameViewDataKey=“SomethingElse”@Fresh:如果我想证明这两个键是相同的不是巧合,我会这么做。在上面的代码中,我强调了它们的独立性。另外,请看我对斯科茨的回答。有一点需要澄清的是,表现并不是完全一样的,而是完全一样的。代码将编译成完全相同的东西。您能详细说明SessionStateWrapper或说明您是否在这方面引用了LukLed的答案吗?我故意避免引用SessionStateWrapper,因为这甚至很难让您了解(至少对我来说是来自Web表单)。关键是,您可以通过在另一个类中使用常量来使用集合中的任何getter,您的整个项目可以一致地访问该类。我很想在博客上写SessionStateWrapper之类的东西,但不是100%我都有
public class BaseController : Controller
{
    public ISessionWrapper SessionWrapper { get; set; }

    public BaseController()
    {
        SessionWrapper = new HttpContextSessionWrapper();
    }
}
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();
    }
}
ViewDataWrapper.ShoppingCart = SessionWrapper.ShoppingCart 
<%= ViewDataWrapper.ShoppingCart %>
<%= Model.ShoppingCart %>
public class SessionKeys
{
    public const string UserDto = "UserDto";
}
UserDto userDto = _sessionStateWrapper.GetItem(SessionKeys.UserDto) as UserDto;