Func <string, bool> bool pour une utilisation dans les arbres d&#39;expression

c# c#-4.0 expression-trees

Question

J'ai un système de construction d'arbre d'expression binaire trop compliqué. Il prend une chaîne et une paire d'objets (Player et World)

Chaque nœud de l’arbre représente une fonction externe qui prend une chaîne, un joueur et un monde, et retourne soit un bool (pour les tests), une chaîne (pour la sortie) ou void (pour les actions).

Mon problème est triple: Premièrement, je dois utiliser quelque chose comme Expression.Condition ou Expression.IfThenElse où le test Expression est de la forme Expression<func<string, Player, World, bool>> plutôt que Expresson<bool> (comme Expression.And serait sortie)

Deuxièmement, je dois être sûr que la référence mémoire de Player et de World reste inchangée. Ainsi, si l'un des nœuds de l'arborescence met à jour quelque chose dans Player, il sera toujours mis à jour au nœud suivant.

Enfin, je dois ajouter toutes les chaînes les unes aux autres.

Si je pouvais coder durement l’arbre, il pourrait ressembler à ceci:

    class Main
    {
        string Foo(string text, World world, Player player)
        {
            string output;
            output += SomeClass.PrintStarting();
            if (SomeClass.Exists(text, world, player))
            {
                output += SomeClass.PrintName(text, world, player);
                SomeClass.KillPlayer(text, world, player);
                if (SomeClass.Exists(text, world, player))
                    output += SomeClass.PrintSurvived(text, world, player);
            }
            else
                output += SomeClass.PrintNotExists(text, world, player);
            return output;
        }
    }
    public class SomeClass
    {
        string PrintStart(string text, World world, Player player)
        {
            return "Starting.\n";
        }

        bool Exists(string text, World world, Player player)
        {
            player.Lives;
        }

        string PrintName(string text, World world, Player player)
        {
            return player.Name + ".\n";
        }

        string PrintSurvived(string text, World world, Player player)
        {
            return player.Name + "died.\n";
        }

        string PrintNotExists(string text, World world, Player player)
        {
            return "This person does not exist.\n";
        }

        void KillPlayer(string text, World world, Player player)
        {
            if (text != "kidding")
                player.Lives = false;
        }
    }

Pour élaborer davantage: J'ai une instance de SomeClass avec toutes ses méthodes test / assign / string. Je vais ensuite créer une liste d' Expression<func<string[], World, Player, bool>> , Expression<Action<string[], World, Player>> et Expression<func<string[], World, Player, string>> et commencez à les jeter ensemble dans un arbre d'expression. La commande réelle de ce qui se passe là où j'ai eu affaire avec moi (par exemple):

    class Main
    {
        string Foo(string text, World world, Player player)
        {
            string output;
            output += SomeClass.PrintStarting();
            if (SomeClass.Exists(text, world, player))
            {
                output += SomeClass.PrintName(text, world, player);
                SomeClass.KillPlayer(text, world, player);
                if (SomeClass.Exists(text, world, player))
                    output += SomeClass.PrintSurvived(text, world, player);
            }
            else
                output += SomeClass.PrintNotExists(text, world, player);
            return output;
        }
    }
    public class SomeClass
    {
        string PrintStart(string text, World world, Player player)
        {
            return "Starting.\n";
        }

        bool Exists(string text, World world, Player player)
        {
            player.Lives;
        }

        string PrintName(string text, World world, Player player)
        {
            return player.Name + ".\n";
        }

        string PrintSurvived(string text, World world, Player player)
        {
            return player.Name + "died.\n";
        }

        string PrintNotExists(string text, World world, Player player)
        {
            return "This person does not exist.\n";
        }

        void KillPlayer(string text, World world, Player player)
        {
            if (text != "kidding")
                player.Lives = false;
        }
    }

Le problème concerne les instructions Condition qui génèrent une erreur car elles ne peuvent pas convertir Func en bool. Je ne sais pas non plus si les paramètres sont transmis (car je n'ai pas pu déboguer)

Réponse acceptée

Après avoir beaucoup manipulé MethodInfo, j'ai découvert que lorsque j'écrivais:

Expression innerTest =
    Expression.Condition(
        Expression.Invoke(Expression.Lambda<Func<string, World, Player, bool>>(testExists, inputString, inputWorld, inputPlayer)),
        Expression.Assign(result, Expression.Call(methodInfo, result, Expression.Lambda<Func<string, World, Player, string>>(textPrintSurvived, inputString, inputWorld, inputPlayer))),
        Expression.Empty());

Expression.Lambda ajoutait une couche de complexité à mon code en transformant Func<string, World, Player, string> en Func<string, World, Player, Func<string, World, Player, string>>

The Expression.Invoke enlevé cette couche supplémentaire qui, au début, m'a dérouté. Avec cette révélation surprenante, j'ai mis cela à jour pour:

Expression innerTest =
    Expression.Condition(
        Expression.Invoke(Expression.Lambda<Func<string, World, Player, bool>>(testExists, inputString, inputWorld, inputPlayer)),
        Expression.Assign(result, Expression.Call(methodInfo, result, Expression.Lambda<Func<string, World, Player, string>>(textPrintSurvived, inputString, inputWorld, inputPlayer))),
        Expression.Empty());

Réponse populaire

J'ai tenté de traduire ce code en tant qu'expression. C'est ce que je suis venu avec. Je ne sais pas si cela fonctionne comme prévu pour tous les cas, mais il compile et semble fonctionner dans mes tests.

// reference method
static string Foo(string text, World world, Player player)
{
    string output = SomeClass.PrintStarting();
    if (SomeClass.Exists(text, world, player))
    {
        output += SomeClass.PrintName(text, world, player);
        SomeClass.KillPlayer(text, world, player);
        if (SomeClass.Exists(text, world, player))
            output += SomeClass.PrintSurvived(text, world, player);
    }
    else
        output += SomeClass.PrintNotExists(text, world, player);
    return output;
}
// reference method
static string Foo(string text, World world, Player player)
{
    string output = SomeClass.PrintStarting();
    if (SomeClass.Exists(text, world, player))
    {
        output += SomeClass.PrintName(text, world, player);
        SomeClass.KillPlayer(text, world, player);
        if (SomeClass.Exists(text, world, player))
            output += SomeClass.PrintSurvived(text, world, player);
    }
    else
        output += SomeClass.PrintNotExists(text, world, player);
    return output;
}

Voici la vue de débogage de l'expression:

// reference method
static string Foo(string text, World world, Player player)
{
    string output = SomeClass.PrintStarting();
    if (SomeClass.Exists(text, world, player))
    {
        output += SomeClass.PrintName(text, world, player);
        SomeClass.KillPlayer(text, world, player);
        if (SomeClass.Exists(text, world, player))
            output += SomeClass.PrintSurvived(text, world, player);
    }
    else
        output += SomeClass.PrintNotExists(text, world, player);
    return output;
}



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi