6

在 aWebControl中,我有一个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 未标记为可序列化。

发生了什么 :

  1. 序列化程序检查字典。它看到它包含一个匿名委托(此处为 lambda)
  2. 由于委托是在一个类中定义的,它会尝试序列化整个类,在本例中为 System.Web.UI.Page
  3. 此类未标记为可序列化
  4. 由于 3,它会引发异常。

有没有方便的解决方案来解决这个问题?由于显而易见的原因,我无法将使用数据源的所有网页标记为 [可序列化]。


编辑1:我不明白的东西。如果我将 存储DictionarySession对象中(使用BinaryFormattervs LosFormatterfor 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;
}
4

2 回答 2

4

好问题。我可以确认您的诊断(稍加修正:基础设施尝试序列化可能包含对您的页面的引用的闭包类)。

您可以定义自己的闭包类并将其序列化:

[Serializable] class Closure { int userId; bool Filter(User u) { ... } };

不过,这并不方便。

我建议您使用不同的模式:不要序列化“代码”。序列化过滤器使用的数据:

class FilterSettings { int userId; int someOtherFiler; string sortOrder; ... }

尽管我无法指出为什么我更愿意凭直觉知道这是一种更好的方法的确切原因。

于 2012-08-28T11:49:18.977 回答
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);

它起作用了,因为现在捕获的变量不再是委托的一部分,而是作为委托的参数给出。

于 2012-12-21T11:09:45.270 回答