У меня слишком сложная система построения дерева двоичных выражений
Требуется строка и пара объектов (игрок и мир)
Каждый узел дерева представляет собой внешнюю функцию, которая принимает строку, игрока и мир и возвращает либо bool (для тестов) строку (для вывода), либо void (для действий)
Моя проблема тройная:
Во-первых, мне нужно использовать что-то вроде Expression.Condition
или Expression.IfThenElse
, где тестовое выражение имеет форму Expression<func<string, Player, World, bool>>
, а не Expresson<bool>
(как выдаст Expression.And
)
Во-вторых, я должен быть уверен, что ссылка на память для Игрока и Мира останется неизменной повсюду - так что если один из узлов в дереве обновит что-то в Игроке, то он все равно будет обновлен на следующем узле.
Наконец, мне нужно добавить все строки, одну к другой.
Если бы я мог жестко закодировать дерево, оно могло бы выглядеть примерно так:
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;
}
}
Для дальнейшей разработки:
У меня есть экземпляр SomeClass со всеми его методами test / assign / string.
Затем я иду и создаю список Expression<func<string[], World, Player, bool>>
, Expression<Action<string[], World, Player>>
и Expression<func<string[], World, Player, string>>
и начинаю бросать их вместе в дерево выражений.
Фактическое упорядочение того, что происходит, где я имел дело, оставляет меня (например):
public string Foo2(string text, World world, Player player)
{
ParameterExpression result = Expression.Parameter(typeof(string), "result");
ParameterExpression inputString = Expression.Parameter(typeof(string[]), "inputString");
ParameterExpression inputWorld = Expression.Parameter(typeof(World), "inputWorld");
ParameterExpression inputPlayer = Expression.Parameter(typeof(Player), "inputPlayer");
System.Reflection.MethodInfo methodInfo = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
Expression textPrintStarting = (Expression<Func<string, World, Player, string>>)((Text, World, Player) => SomeClass.PrintStarting(Text, World, Player));
Expression testExists = (Expression<Func<string, World, Player, bool>>)((Text, World, Player) => SomeClass.Exists(Text, World, Player));
Expression textPrintName = (Expression<Func<string, World, Player, string>>)((Text, World, Player) => SomeClass.PrintName(Text, World, Player));
Expression killPlayer = (Expression<Action<string, World, Player>>)((Text, World, Player) => SomeClass.KillPlayer(Text, World, Player));
Expression textPrintSurvived = (Expression<Func<string, World, Player, string>>)((Text, World, Player) => SomeClass.PrintSurvived(Text, World, Player));
Expression textPrintNotExist = (Expression<Func<string, World, Player, string>>)((Text, World, Player) => SomeClass.PrintNotExists(Text, World, Player));
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 success =
Expression.Block(
Expression.Assign(result, Expression.Call(methodInfo, result, Expression.Lambda<Func<string, World, Player, string>>(textPrintName, inputString, inputWorld, inputPlayer))),
Expression.Lambda<Action<string, World, Player>>(killPlayer, inputString, inputWorld, inputPlayer),
innerTest);
Expression failure =
Expression.Assign(result, Expression.Call(methodInfo, result, Expression.Lambda<Func<string, World, Player, string>>(textPrintNotExist, inputString, inputWorld, inputPlayer)));
Expression outerTest =
Expression.Condition(
Expression.Invoke(Expression.Lambda<Func<string, World, Player, bool>>(testExists, inputString, inputWorld, inputPlayer)),
success,
failure);
Expression finalExpression =
Expression.Block(
Expression.Assign(result, Expression.Call(methodInfo, result, Expression.Lambda<Func<string, World, Player, string>>(textPrintStarting, inputString, inputWorld, inputPlayer))),
outerTest);
return Expression.Lambda<Func<string, World, Player, string>>(
Expression.Block(new[] { result },
finalExpression)).Compile()(text, world, player);
}
Проблема связана с операторами Condition
, которые выдают ошибку, поскольку не могут преобразовать из Func в bool.
Я также не уверен, передаются ли параметры (так как я не смог отладить)