2012-08-28 3 views
6

In einem WebControl, habe ich eine Eigenschaft Filters wie folgt definiert:Gibt es eine Möglichkeit, einen anonymen Delegaten in einem Viewstate zu speichern?

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; 
    } 
} 

Diese webcontrol ist ein DataSource, ich diese Eigenschaft erstellt, weil ich die Möglichkeit haben will, einfach Daten zu filtern, zB:

//in page load  
DataSource.Filters.Add("userid", u => u.UserID == 8); 

Es funktioniert großartig, aber wenn ich Code dies zu ändern:

//in page load  
int userId = int.Parse(DdlUsers.SelectedValue); 
DataSource.Filters.Add("userid", u => u.UserID == userId); 

wor Es ist nicht ks mehr, ich diesen Fehler:

Typ System.Web.UI.Page in Assembly '...' ist nicht markiert als serializable.

Was ist passiert:

  1. Der Serializer inspizieren das Wörterbuch. Es sieht, dass es einen anonymen Delegaten enthält (hier Lambda)
  2. Da der Delegat in einer Klasse definiert ist, versucht er die gesamte Klasse zu serialisieren, in diesem Fall System.Web.UI.Page
  3. Diese Klasse ist nicht als markiert Serializable
  4. Es wirft eine Ausnahme, weil der 3.

gibt es eine bequeme Lösung, dieses Problem zu lösen? Ich kann nicht alle Webseiten markieren, wo ich die Datenquelle aus offensichtlichen Gründen als [serialisierbar] benutze.


EDIT 1: etwas, das ich nicht verstehe. Wenn ich das Dictionary im Objekt Session (das eine BinaryFormatter vs LosFormatter für ViewState verwenden) speichern, funktioniert es! Ich habe keine Ahnung, wie es möglich ist. Vielleicht BinaryFormatter kann jede Klasse serialisieren, auch diese, die nicht [serializable] sind?


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; 
} 
+0

"es funktioniert! Ich habe keine Ahnung wie ...": Sitzungsdaten bleiben serverseitig, im Speicher. Es wird zu brechen beginnen, wenn Sie zu 2 Servern wechseln. –

+0

thx für die info – tigrou

Antwort

0

ich eine Lösung gefunden, hier ist, wie ich es tat:

I Wörterbuch Definition wie folgt geändert:

Dictionary<string, KeyValuePair<Func<T, object[], bool>, object[]>> 

(KeyValuePair ist serializable, wie Dictionary)

und erstellt ein neu Add() Funktion:

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); 

Es funktioniert, weil jetzt erfassten Variablen nicht mehr sind die Delegierten, ein Teil aber als Parameter des Delegaten gegeben:

Jetzt können Filter auf diese Weise eingestellt werden.

4

Gute Frage: kleinster Code, um das Problem zu reproduzieren. Ich kann Ihre Diagnose bestätigen (mit einer winzigen Korrektur: Die Infrastruktur versucht, die Schließklasse zu serialisieren, die wahrscheinlich einen Verweis auf Ihre Seite enthält).

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

Das ist nicht bequem, aber:

Sie können Ihre eigene Schließung Klasse und haben die serialisierten definieren.

Ich schlage vor, dass Sie ein anderes Muster verwenden: "Code" nicht serialisieren.Serialisiert wird, die durch die Filter verwendeten Daten:

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

Obwohl ich nicht auf den genauen Grund zeigen, warum ich es vorziehen würde, dass ich intuitiv wissen, dass es ein besserer Ansatz.

+0

Danke für Sie antworten. Ich bin mir nicht sicher, wie der zweite Vorschlag funktionieren wird. Wer instanziiert und hält die Instanz der FilterSettings-Klasse? Wenn es die Seite gibt, gibt es kein Risiko, dass Serializer die Seite auch erreicht? Können Sie mehr Code zur Verwendung dieser Lösung bereitstellen? – tigrou

+0

Das Speichern einer Klasse, deren Felder Sie genau steuern, wird nie auf die Seite verweisen. Es gibt keine Möglichkeit, dass der Serializer die Seite von Closure oder FilterSettings aus erreichen kann. – usr

+0

Ich kann es immer noch nicht mit Ihren Vorschlägen arbeiten. Ich habe am Ende der Frage ein Beispielcode hinzugefügt, der das Problem reproduzieren wird. Kannst du einen Blick darauf werfen und mir einen Hinweis geben? – tigrou