Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有办法在viewstate中存储匿名委托?_C#_Serialization_Delegates_Webforms_Viewstate - Fatal编程技术网

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未标记为 可序列化

发生了什么:

  • 序列化程序检查字典。它看到它包含一个匿名委托(此处为lambda)
  • 由于委托是在类中定义的,因此它尝试序列化整个类,在本例中是System.Web.UI.Page
  • 此类未标记为可序列化
  • 它抛出一个异常,原因是3
  • 有什么方便的解决方案吗?我无法将使用数据源的所有网页标记为[serializable],原因很明显



    编辑1:我不明白的事情。如果我将
    字典
    存储在
    会话
    对象中(该对象使用
    二进制格式化程序
    vs
    LosFormatter
    用于
    视图状态
    ),它会工作!我不知道这怎么可能。也许
    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);