Serialize Ausdrucksbaum

c# expression-trees lambda serialization

Frage

Ich mache ein verteiltes System in c # und bin auf eine Barriere gestoßen.

Ich muss Prädikat mit Typ serialisieren können

Predicate<ICollection<IEntity>> p = (entities => entities.OfType<Person>().Count() <= 3);

Ich glaube, das ist in .net nicht möglich, also ist meine Frage, ob es irgendwelche Rahmen gibt, die den Trick machen können.

Ich habe bereits ein paar Frameworks ausprobiert, aber ich habe immer wieder das Problem, dass es nicht möglich ist, Prädikate zu serialisieren, die eine Sammlung oder Liste aufnehmen

Hoffe, dass jemand eine Lösung kennt. Habe seit ein paar Wochen mit diesem Problem aufgehört ...

Akzeptierte Antwort

Meine Lösung:

Nachdem ich das Problem lange Zeit gelöst hatte, gelang es mir endlich, mein Problem mit json.net und Aq.ExpressionJsonSerializer ( https://github.com/aquilae/expression-json-serializer ) zu lösen.

public class JsonNetAdapter : IOconSerializer
{
    private readonly JsonSerializerSettings _settings;

    public JsonNetAdapter(JsonSerializerSettings settings = null)
    {
        var defaultSettings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Objects};
        defaultSettings.Converters.Add(new ExpressionJsonConverter(Assembly.GetAssembly(typeof(IOconSituation))));
        _settings = settings ?? defaultSettings;
    }

    public string Serialize<T>(T obj)
    {
        return JsonConvert.SerializeObject(obj, _settings);
    }

    public T Deserialize<T>(string json)
    {
        return JsonConvert.DeserializeObject<T>(json, _settings);
    }
}

Klappt wunderbar!


Beliebte Antwort

Ich habe das schon mal versucht. Es wird einige Arbeit erfordern, aber Sie können Ihr eigenes Protokoll entwickeln, um Prädikate über ein Netzwerk zu übergeben.

Zuerst müssen Sie den Typ Ihrer p Variablen in einen Expression<TDelegate> damit er dekonstruiert werden kann:

Expression<Predicate<ICollection<IEntity>>> p = (entities => entities.OfType<Person>().Count() <= 3);

VisitExpression(p);

Der C # -Compiler Expression<TDelegate> , dass Sie einer Expression<TDelegate> ein Lambda Expression<TDelegate> , und es wird tatsächlich eine Ausdrucksbaumstruktur für Sie erstellen.

Jetzt können Sie den Ausdrucksbaum laufen lassen und ihn zu Ihrem benutzerdefinierten Protokoll serialisieren. Ich werde hier einen StringBuilder , um ein JSON-Objekt zu erstellen (für eine einfache Deserialisierung).

StringBuilder sb = new StringBuilder();

void VisitExpression(Expression e)
{
    switch (e.ExpressionType)
    {
    case ExpressionType.And:
        return VisitBinaryExpression(e As BinaryExpression);

    ...
    }
}

void VisitBinaryExpression(BinaryExpression e)
{
    sb.AppendLine("{");
    switch (e.ExpressionType)
    {
    case ExpressionType.And:
        sb.Append("\"Type\": \"And\",");
        break;

    ...
    }
    sb.Append("\"Left\":");
    VisitExpression(e.Left); sb.Append(",");
    sb.Append("\"Right\":");
    VisitExpression(e.Right);
    sb.AppendLine("}");
}

Abhängig davon, wie Ihr verteiltes System Sammlungen und Listen verarbeitet, müssen Sie die entsprechende Logik implementieren, wenn Sie den Ausdrucksbaum durchlaufen. Ich würde mit typeof(IEnumerable<>).MakeGenericType(typeof(IEntity)).IsAssignableFrom(typeToTest) .

Beim Serialisieren müssen Sie die vollständigen Namen der Typen, Methoden und Überladungen über das Netzwerk senden. Wahrscheinlich möchten Sie sicherstellen, dass jeder Rechenknoten auf dieselben Bibliotheken verweist, so dass Sie die Typen und Methoden korrekt auflösen können, wenn Sie alles deserialisieren.

Wenn Sie die Deserialisierung abgeschlossen haben, System.Linq.Expressions Sie die Ausdrucksstruktur auf dem Remote-Host mithilfe der Klassen im System.Linq.Expressions Namespace neu. Kompilieren und führen Sie dann den Ausdruck aus, der Lambda.Compile() .



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow