C# 有没有办法在viewstate中存储匿名委托?
在C# 有没有办法在viewstate中存储匿名委托?,c#,serialization,delegates,webforms,viewstate,C#,Serialization,Delegates,Webforms,Viewstate,在网络控制中,我有一个属性过滤器,定义如下: public Dictionary<string, Func<T, bool>> Filters { get { Dictionary<string, Func<T, bool>> filters = (Dictionary<string, Func<T, bool>>)ViewState["filters"];
网络控制
中,我有一个属性过滤器
,定义如下:
public Dictionary<string, Func<T, bool>> Filters
{
get
{
Dictionary<string, Func<T, bool>> filters =
(Dictionary<string, Func<T, bool>>)ViewState["filters"];
if (filters == null)
{
filters = new Dictionary<string, Func<T, bool>>();
ViewState["filters"] = filters;
}
return filters;
}
}
但是,如果我将代码更改为:
//in page load
int userId = int.Parse(DdlUsers.SelectedValue);
DataSource.Filters.Add("userid", u => u.UserID == userId);
它不再工作了,我得到了这个错误:
程序集“…”中的类型System.Web.UI.Page未标记为
可序列化
发生了什么:
编辑1:我不明白的事情。如果我将
字典
存储在会话
对象中(该对象使用二进制格式化程序
vsLosFormatter
用于视图状态
),它会工作!我不知道这怎么可能。也许BinaryFormatter
可以序列化任何类,即使是那些不[serializable]
的类
编辑2:再现问题的最小代码:
void test()
{
Test test = new Test();
string param1 = "parametertopass";
test.MyEvent += () => Console.WriteLine(param1);
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, test); //bang
}
}
[Serializable]
public class Test
{
public event Action MyEvent;
}
好问题。我可以确认您的诊断(只需一个小小的更正:基础结构尝试序列化可能包含对页面引用的闭包类) 您可以定义自己的闭包类并将其序列化:
[Serializable] class Closure { int userId; bool Filter(User u) { ... } };
但这并不方便
我建议您使用不同的模式:不要序列化“代码”。序列化筛选器使用的数据:
class FilterSettings { int userId; int someOtherFiler; string sortOrder; ... }
虽然我无法指出我希望直觉上知道这是一种更好的方法的确切原因。我找到了一个解决方案,下面是我如何做到的: 我修改了字典定义如下:
Dictionary<string, KeyValuePair<Func<T, object[], bool>, object[]>>
现在可以通过以下方式设置过滤器:
int userId = int.Parse(DdlUsers.SelectedValue);
DataSource.Filters.Add("userid", (u, args) => u.UserID == (int)args[0], userId);
它可以工作,因为现在捕获的变量不再是委托的一部分,而是作为委托的参数提供的。感谢您的回答。我不确定第二个建议会如何运作。谁将实例化并持有FilterSettings类的实例?如果是页面,序列化程序是否也会到达页面?您能否提供更多关于如何使用此解决方案的代码?存储一个您精确控制其字段的类将永远不会引用该页。序列化程序无法从闭包或过滤器设置开始访问页面。即使有您的建议,我仍然无法使其工作。我在问题的底部添加了一个代码示例,它将重现这个问题。你能看一下并给我提示吗?我猜编译器创建的闭包类是不可序列化的。这就是为什么你需要自己动手。如果要序列化函数,请使该函数成为闭包类的实例成员,并创建如下委托:new Action(myClosure.InstanceMethod)。您不能使用lambda。“它工作!我不知道如何…”:会话数据保留在服务器端内存中。当您移动到2台以上的服务器时,它将开始中断。
public void Add(string key, Func<T, object[], bool> filter, params object[] args)
{
this.Add(key, new KeyValuePair<Func<T, object[], bool>, object[]>
(filter, args));
}
int userId = int.Parse(DdlUsers.SelectedValue);
DataSource.Filters.Add("userid", (u, args) => u.UserID == (int)args[0], userId);