хорошая ли идея создать перечисление для имен ключей значений сеанса?
-
19-08-2019 - |
Вопрос
вместо того, чтобы делать
session("myvar1") = something
session("myvar2") = something
session("myvar3") = something
session("myvar4") = something
делается
enum sessionVar
myvar1
myvar2
myvar3
myvar4
end enum
session(sessionVar.myvar1.tostring) = something
session(sessionVar.myvar2.tostring) = something
session(sessionVar.myvar3.tostring) = something
session(sessionVar.myvar4.tostring) = something
было бы лучше?
Решение
Вместо использования констант для ключей сеанса я использую свой собственный типобезопасный объект сеанса, который выглядит следующим образом (извините, это на C#, версию VB см. ниже):
public class MySession
{
// Private constructor (use MySession.Current to access the current instance).
private MySession() {}
// Gets the current session.
public static MySession Current
{
get
{
MySession session = HttpContext.Current.Session["__MySession__"] as MySession;
if (session == null)
{
session = new MySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// My session data goes here:
public string MyString { get; set; };
public bool MyFlag { get; set; };
public int MyNumber { get; set; };
}
Всякий раз, когда мне нужно прочитать/записать что-либо в/из сеанса, я могу использовать свой типобезопасный объект сеанса следующим образом:
string s = MySession.Current.MyString;
s = "new value";
MySession.Current.MyString = s;
Такое решение дает ряд преимуществ:
- У меня есть типобезопасный сеанс (больше нет приведения типов)
- Я могу документировать все данные сеанса (комментируя общедоступные свойства в MySession).
- При добавлении нового элемента в сеанс мне не нужно искать решение, чтобы проверить, не использовался ли уже где-то еще тот же сеансовый ключ.
Обновлять:Вот версия VB (автоматически преобразованная из версии C#).Извините, но я не знаю VB и поэтому не знаю, как писать свойства в VB:
Public Class MySession
' Private constructor (use MySession.Current to access the current instance).
Private Sub New()
End Sub
' Gets the current session.
Public Shared ReadOnly Property Current() As MySession
Get
Dim session As MySession = TryCast(HttpContext.Current.Session("__MySession__"), MySession)
If session = Nothing Then
session = New MySession()
HttpContext.Current.Session("__MySession__") = session
End If
Return session
End Get
End Property
' My session data goes here:
Public MyString As String
Public MyFlag As Boolean
Public MyNumber As Integer
End Class
Другие советы
Только если эти значения связаны. В противном случае используйте простые старые константы.
Как насчет: -
public static class SessionVar
{
public static readonly string myVar1 = "myVar1";
public static readonly string myVar2 = "myVar2";
public static readonly string myVar3 = "myVar3";
public static readonly string myVar4 = "myVar4";
}
Это позволяет вам использовать: -
session(SessionVar.myVar1) = something;
Я использовал подобные классы для создания типизированной оболочки сессии / кэша. Возможно, вам понадобится добавить дополнительный код в get / set, но я оставлю это на ваше усмотрение.
internal class SessionHelper
{
private const string myVar1Key = "myvar1";
public static int MyVar1
{
get
{
return (int)System.Web.HttpContext.Current.Session[myVar1Key];
}
set
{
System.Web.HttpContext.Current.Session[myVar1Key] = value;
}
}
}
Извините за C # ....
Для простоты удаления всех ссылок на строковые ключи я бы использовал глобальные статические / общие константы, видимые в области приложения. Р>
В противном случае простая типизированная оболочка со строгой типизацией для переменных сеанса является превосходной альтернативой, и она намного более дружественна к ООП, учитывая, что вы получаете intellisense и совместимость с Object Browser.
Единственный способ увидеть большое значение enum - это использовать его для индексации в массиве или аналогичном списке. Но даже тогда вы должны привести enum к int.
Таким образом, у вас может быть массив, который вы загружаете при запуске приложения со всеми ключами переменных сеанса, а затем перечисление для индексов. Однако, учитывая, что объект Session является производным от HttpSessionState, который является производным от IEnumerable, вы должны иметь возможность просто выполнять цикл foreach над переменными сеанса, если вам нужно.
Я понимаю, что этот вопрос задавали некоторое время назад и " answer " уже был выбран Но я только столкнулся с этим. Ответ Мартина хорош. Однако, чтобы помочь любому, кто столкнется с этим в будущем, если вы действительно хотите ловкий способ иметь дело с сессией, прочитайте это post . Я не думаю, что вы найдете что-нибудь проще.
Я придумал решение, которое позволяет избежать некоторых недостатков других опубликованных решений, сохраняя структуру переменных сеанса нетронутой.Это просто безопасный для типов ярлык для получения и установки переменных сеанса.
Это C#, но в конце я опубликовал автоматически сгенерированный VB.NET.
Лучшие решения, которые я видел (принятый ответ и ответ TheObjectGuy), требуют специального класса, который хранится в переменной сеанса, а затем извлекается из сеанса для доступа к его свойствам с помощью чего-то вроде MySessionClass.Current.MyProperty.
Проблема в том, что если вы в настоящее время используете (или можете использовать в будущем) что-то иное, чем режим состояния сеанса InProc (см. https://msdn.microsoft.com/en-us/library/ms178586%28v=vs.140%29.aspx), весь класс должен будет пройти сериализацию, чтобы получить доступ к одному свойству.
Кроме того, это означает, что вы потеряете реализации IEnumerable и ICollection, предлагаемые реальным сеансом, если они вам нужны.С помощью моего решения вы можете просто получить доступ к реальному сеансу, если вам нужна эта функция.
Вы можете легко использовать эти переменные сеанса, и они безопасны по типу.Его можно использовать вместе с такими операторами, как Session["MyProperty"], которые позволяют конвертировать существующий проект по одной ссылке за раз.Так:
int myInt = (int)Session["MyInt"];
Session["MyInt"] = 3;
становится:
int myInt = SessionVars.MyInt;
SessionVars.MyInt = 3;
Вот настоящий класс.Для CallerMemberName требуется .NET 4.5, но даже если вы используете более старую версию, вы все равно можете управлять ею, явно передав имя свойства.Кроме того, типы свойств должны иметь значение NULL, чтобы они действовали точно так же, как стандартные вызовы Session["MyProp"], поскольку неустановленный
public static class SessionVars
{
private static T Get2<T>([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (HttpContext.Current.Session[propertyName] == null)
{
return default(T);
}
return (T)HttpContext.Current.Session[propertyName];
}
private static void Set2<T>(T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
HttpContext.Current.Session[propertyName] = value;
}
public static int MyInt { get { return Get2<int>(); } set { Set2<int>(value); } }
public static bool MyBool { get { return Get2<bool>(); } set { Set2<bool>(value); } }
public static string MyString { get { return Get2<string>(); } set { Set2<string>(value); } }
}
Я даже написал фрагмент кода, чтобы облегчить добавление этих свойств:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>SessionVars Property</Title>
<Author>kevinpo</Author>
<Shortcut>sv</Shortcut>
<Description>Adds a property for use in a SessionVars class</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<Default>PropertyName</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[public static $type$ $property$ { get { return Get2<$type$>(); } set { Set2<$type$>(value); } }]]>
</Code>
</Snippet>
</CodeSnippet>
Я знаю C#, поэтому этот VB.NET просто автоматически конвертируется http://converter.telerik.com/:
Public NotInheritable Class SessionVars
Private Sub New()
End Sub
Private Shared Function Get2(Of T)(<System.Runtime.CompilerServices.CallerMemberName> Optional propertyName As String = "") As T
If HttpContext.Current.Session(propertyName) Is Nothing Then
Return Nothing
End If
Return DirectCast(HttpContext.Current.Session(propertyName), T)
End Function
Private Shared Sub Set2(Of T)(value As T, <System.Runtime.CompilerServices.CallerMemberName> Optional propertyName As String = "")
HttpContext.Current.Session(propertyName) = value
End Sub
Public Shared Property MyInt() As Integer
Get
Return Get2(Of Integer)()
End Get
Set
Set2(Of Integer)(value)
End Set
End Property
Public Shared Property MyBool() As Boolean
Get
Return Get2(Of Boolean)()
End Get
Set
Set2(Of Boolean)(value)
End Set
End Property
Public Shared Property MyString() As String
Get
Return Get2(Of String)()
End Get
Set
Set2(Of String)(value)
End Set
End Property
End Class
'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: @telerik
'Facebook: facebook.com/telerik
'=======================================================