评估代码内联(或使用反射)

时间:2016-05-17 20:08:00

标签: c# reflection codedom

为了解决问题的核心,我已经对此进行了简化:

我有一个需要填充属性的控件。不幸的是,这些值都位于CodeDom.CodeStatements中。

所以我真的必须通过使用这样的代码来捕获值:

static string GenerateCode(CodeStatementCollection statements, Control control)
      {
         var writer = new StringWriter();

         var compiler = new CSharpCodeProvider();

         foreach (CodeStatement statement in statements)
         {
            var codeAssignStatement = statement as System.CodeDom.CodeAssignStatement;

            var left = codeAssignStatement?.Left as System.CodeDom.CodePropertyReferenceExpression;

            if (left == null)
            {
               continue;
            }

            var right = codeAssignStatement.Right as System.CodeDom.CodeObjectCreateExpression;

            if (right == null)
            {
               continue;
            }

            var expressionWriter = new StringWriter();
            compiler.GenerateCodeFromExpression(right,expressionWriter,null);
            var expression = expressionWriter.ToString();

            control.SetPropertyValue(left.PropertyName, expression);

            compiler.GenerateCodeFromStatement(statement, writer, null);

         }

         return writer.ToString();
      }

请注意,代码使用的是反射,SetPropertyValue实际上是一个扩展方法:

public static void SetPropertyValue(this object obj, string propName, object value)
      {
         obj.GetType().GetProperty(propName).SetValue(obj, value, null);
      }

但这只有在值是文字值而不是表达式时才有效。

在运行时,我从CodeDom语句获得的是一个表达式,控件也是一个按钮。

  

Button.Location = New System.Drawing.Point(12,12);

所以在上面的代码示例中,表达式=" New System.Drawing.Point(12,12)"

现在我不想通过一系列IF语句来首先确定类型。

是否可以使用反射基于表达式设置属性?

如果没有,是否可以在.net中使用某种Eval功能将其关闭?

2 个答案:

答案 0 :(得分:2)

要从脚本创建代码,您需要动态编译该方法。

您要做的第一件事就是将方法编译成MethodInfo。 您可以创建一个方法来完成此任务。

public static MethodInfo CreateMethodInfo(string script, string className, string methodName)
{
    using (var compiler = new CSharpCodeProvider())
    {
        var parms = new CompilerParameters
        {
            GenerateExecutable = false,
            GenerateInMemory = true,
            ReferencedAssemblies = { "System.Drawing.dll" }
        };
        return compiler.CompileAssemblyFromSource(parms, script)
            .CompiledAssembly.GetType(className)
            .GetMethod(methodName);
    }
}

完成此操作后,您可以像这样使用它。

var script = "public class Methods{public static System.Drawing.Point DoSomething(){return new System.Drawing.Point(12, 12);}}";

var method = CreateMethodInfo(script, "Methods", "DoSomething");

现在method变量保存了您的MethodInfo,因此您只需要调用它。

Button.Location = (Point)method.Invoke(null, null);

答案 1 :(得分:0)

我认为你可以试试LINQ Expression。 https://msdn.microsoft.com/en-us/library/bb335710(v=vs.110).aspx

将您的方法更改为以下内容:

#include<vector>
#include "../Header Files/SinglePlayer.h"

SinglePlayer::SinglePlayer()
{

}

int myRand(int low, int high) 
{
   srand(time(NULL));
   return rand() % (high - low + 1) + low;
}

void SinglePlayer::startGame()
{
    cout << "Starting Single Player........." << endl;
    cout << "Starting out with two cards...." << endl;
    int randomCardStarterOnePlayer = myRand(0,10);
    int randomCardStarterTwoPlayer = myRand(0,10);
    int randomCardStarterOneAI = myRand(0,10);
    int randomCardStarterTwoAI = myRand(0,10);
    this -> calculateRandomStarter(randomCardStarterOnePlayer,
                                   randomCardStarterTwoPlayer,
                                   randomCardStarterOneAI,
                                   randomCardStarterTwoAI);
    cout << "You Start out with " << amountPlayer << endl;
    cout << "Computer Starts out with " << amountAI << endl;
}

void SinglePlayer::calculateRandomStarter(int randomOnePlayer, int randomTwoPlayer, int randomOneAI, int randomTwoAI)
{
    amountPlayer = amountPlayer + randomOnePlayer + randomTwoPlayer;
    playerCards.push_back(randomOnePlayer);
    playerCards.push_back(randomTwoPlayer);

    amountAI = amountAI + randomOneAI + randomTwoAI;
    AICards.push_back(randomOneAI);
    AICards.push_back(randomTwoAI);
}

SinglePlayer::~SinglePlayer()
{
}

在表达式中配置和编译委托函数,并在SetPropertyValue()中调用它。