6

では、次のように定義され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;
    }
 }

この Web コントロールは です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. シリアライザはディクショナリを検査します。匿名のデリゲート (ここではラムダ) が含まれていることがわかります
  2. デリゲートはクラスで定義されているため、クラス全体 (この場合は System.Web.UI.Page) をシリアル化しようとします。
  3. このクラスはシリアライズ可能としてマークされていません
  4. 3のため、例外がスローされます。

これを解決する便利な解決策はありますか? 明らかな理由により、データソースを使用するすべての Web ページを [シリアル化可能] としてマークすることはできません。


EDIT 1 :私が理解していないもの。をオブジェクト(vs forを使用)に保存するDictionaryと、機能します!どうすればそれが可能かわかりません。たぶん、そうでない人でも、どのクラスでもシリアライズできますか?SessionBinaryFormatterLosFormatterViewStateBinaryFormatter[serializable]


EDIT 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

良い質問。私はあなたの診断を確認できます (1 つの小さな修正: インフラストラクチャは、おそらくあなたのページへの参照を含むクロージャー クラスをシリアル化しようとします)。

独自のクロージャー クラスを定義して、それをシリアル化することができます。

[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 の定義を次のように変更しました。

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 に答える