在WebControl
中,我有一个定义如下的属性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;
}
}
这个webcontrol是DataSource
,我创建了这个属性,因为我希望能够轻松过滤数据,例如:
//in page load
DataSource.Filters.Add("userid", u => u.UserID == 8);
但是,如果我将代码更改为:
,它的效果很好//in page load
int userId = int.Parse(DdlUsers.SelectedValue);
DataSource.Filters.Add("userid", u => u.UserID == userId);
它不再起作用了,我收到了这个错误:
程序集'...'中的类型System.Web.UI.Page未标记为 序列化的。
发生了什么:
有没有方便的解决方案来解决这个问题?由于显而易见的原因,我无法将所有使用数据源的网页标记为[serializable]。
编辑1 :我不明白的事情。如果我将Dictionary
存储在Session
对象中(对BinaryFormatter
使用LosFormatter
vs ViewState
),它就可以了!我不知道怎么可能。也许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;
}
答案 0 :(得分:4)
好问题。我可以确认您的诊断(通过一个小小的更正:基础结构尝试序列化闭包类,其中可能包含对您页面的引用)。
您可以定义自己的闭包类并将其序列化:
[Serializable] class Closure { int userId; bool Filter(User u) { ... } };
但这不方便。
我建议你使用不同的模式:不要序列化“代码”。序列化过滤器使用的数据:
class FilterSettings { int userId; int someOtherFiler; string sortOrder; ... }
虽然我无法指出我更倾向于直觉地知道这是一种更好的方法的确切原因。
答案 1 :(得分:0)
我找到了一个解决方案,这就是我如何做到的:
我修改了这样的字典定义:
Dictionary<string, KeyValuePair<Func<T, object[], bool>, object[]>>
(KeyValuePair
可序列化,就像Dictionary
)
并创建了一个新的Add()
函数:
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);
它有效,因为现在捕获的变量不再是委托的一部分,而是作为委托的参数给出。