我有一个对象MySession
,它有一个哈希表,用于存储任意类型的任意属性。对象定义的相关部分是:
public class MySession
{
private Hashtable _sessionVars;
///
/// Set and retrieve session variables ala the traditional session managers.
/// So, SessionObject["var1"] can be used to set or retrieve a value for var1.
///
/// Name of the variable to access.
/// An object that was stored in the session under key.
public object this[string key] {
get {
if (_sessionVars.ContainsKey(key)) {
return this._sessionVars[key];
}
return null;
}
set {
if (this._sessionVars.ContainsKey(key)) {
this._sessionVars.Remove(key);
}
this._sessionVars[key] = value;
}
}
}
令人烦恼的是,当我想使用它们时,我必须正确地转换属性。例如:
MySession session = new MySession();
if ( (bool)session["valid"] == true ) { /* do something fun */ }
我宁愿能够做到:
MySession session = new MySession();
if ( session["valid"] == true ) { /* do something fun */ }
是否可以在C#中执行此操作?如果是这样,怎么样?
更新:我不想使用显式方法来访问属性。关键是能够尽可能简单地访问它们。不像session.GetProperty(name, type)
或其他东西。
答案 0 :(得分:3)
如果你仔细想想,你会发现这本质上是不可能的。
如果你写session[someTextbox.Text]
怎么办?
如果为同一标识符分配两种不同的类型,该怎么办?
编译此类代码将涉及解决halting problem以确定每个字符串的类型。
相反,您可以在HttpContext.Current.Session
周围创建一个强类型的包装类,其属性包含其getter中的强制转换。
答案 1 :(得分:2)
如果您使用的是.Net Framework 4.0,那么您可以通过从DynamicObject派生MySession类并覆盖必要的方法来实现。
以下是代码:
public class MySession : DynamicObject
{
//Why not use Dictionary class?
private Hashtable _sessionVars = new Hashtable();
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
//You can make it private so that users do not use strings directly.
public object this[string key]
{
get
{
if (_sessionVars.ContainsKey(key))
{
return this._sessionVars[key];
}
return null;
}
set
{
if (this._sessionVars.ContainsKey(key))
{
this._sessionVars.Remove(key);
}
this._sessionVars[key] = value;
}
}
}
这就是你如何使用它:
dynamic ses = new MySession();
ses.number = 5;
ses.boolean = true;
Console.WriteLine(ses.number > 4);
if (ses.boolean)
{
Console.WriteLine(ses.number - 1);
}
Console.ReadKey();
无需使用字符串转换或使用字符串来访问新字段!如果您正在使用Resharper,您也将获得现有字段的智能感知。如果您需要更多功能,也可以覆盖其他成员。
答案 2 :(得分:0)
我个人最终还是要处理尚未设置会话变量的场景。因此,我最终得到了一个如下所示的方法:
public class MySession
{
...
public T GetValue<T>(string key, T defaultValue)
{
return _sessionVars.ContainsKey(key) ? this._sessionVars[key] as T : defaultValue;
}
}
然后可以推断T.然后可以像这样调用它(不需要强制转换):
if (mySession.GetValue("valid", false))
{
// fun stuff here
}
我不确定“T”是否有效。如果没有,你可以将它投射到(T)之前完成。如果你有继承的类等等,那么“as T”会很好。
我通常派出一个像mySession这样的类,并在属性getter中调用base.GetValue(),我将其从派生类中公开。
答案 3 :(得分:0)
如果您传递字符串(或任何类型的对象)键,则无法执行; indexer方法只能返回一个特定的类型,因此你不可能让它返回一个字符串或一个double。例如。
有两个选项:一,如果这是一个不需要任意键灵活性的有限范围类,那么你可以只添加显式属性 - 如果你想要的话,可能仅适用于常用属性仍然可以回到object
- 返回索引器。
或者,您可以添加一个通用的Get方法,如下所示:
public T GetValue<T>(object key) {
if(_hashSet[key] is T) {
return (T)_hashSet[key];
}
throw new InvalidCastException();
}
但是,这并没有给你带来多少,因为你仍然需要指定类型名称,你只是将它从强制转换为通用参数。
编辑:当然,您希望如何处理无效的强制转换取决于您,但抛出异常会模仿直接强制转换的行为。正如在另一个答案中提到的那样,如果你还在签名中指定了类型为T的参数,那么它将从该参数中获得正确的类型。
答案 4 :(得分:0)
添加会话的简单且最佳方式
public static void Add<T>(string key, T value)
{
var current = HttpContext.Current;
if (current == null) return;
current.Session.Add(key, value);
}
实施例
public Model User
{
private string searchText
{
get { return SessionHelper.Get<string>("searchText"); }
set { SessionHelper.Add("searchText", value); }
}
}