【问题标题】:How to compile string conditions in aspects如何在方面编译字符串条件
【发布时间】:2012-02-03 14:12:46
【问题描述】:

我有一个简单的课程。而且我必须为一些方法和属性添加一些条件。例如:

public class Example
{
  public Boolean Condition {get; set;}
  public Double ConditionValue {get; set;}

  [Verify("!Condition && ConditionValue>5")]
  public void DoSomthing()
  { ... }
}

我想检查一个方面属性中的条件(例如,“!Condition && ConditionValue>5”)。我无法将动作/功能赋予属性,因此我给出了一个简单的字符串。我需要把这个字符串翻译成一个条件:

[Serializable]
public class MyAspectAttribute : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionArgs args)
    {
        if (!this.Condition && this.ConditionValue>5) // If-statment from string, this is the problem...
        { ... }
    }
}  

如何从字符串中提取真正的 if 语句?我看到了一些解决方案,但我不确定它们是否正常:

  1. 使用运行时编译器,例如CSharpCodeProvider。
  2. 使用诸如http://flee.codeplex.com/之类的库
  3. 还有什么...?

我怎样才能优雅地做到这一点?谢谢!

更新:我已经编辑了关于建议的问题... Upd2:我尝试验证我的代码,我可以这样做:

public class Example2
    {
      public Boolean Condition {get; set;}

      [LoggingIf("Condition")]
      public void DoSomthing1()
      { ... }

      [PrintReportIf("!Condition")]
      public void DoSomthing2()
      { ... }
    }

【问题讨论】:

  • 为什么在这种情况下自定义属性?
  • 我尝试为班级成员添加一些逻辑。这是可行的,但我正在寻找一个很好的解决方案......以及如何在没有属性的情况下为很多(!)属性和方法添加一些逻辑......?
  • 在属性中包含代码后,您期望什么会调用您的代码?属性对它们装饰的成员一无所知,也没有任何“调用”属性。他们只指定元数据。
  • Postsharp 可以以不同方式使用此元数据... =) 一种方法 - 将此字符串作为 if-statement(?) 插入方法主体...
  • @DragonFire - 如果您使用 PostSharp,那么有什么问题?

标签: c# if-statement compilation conditional postsharp


【解决方案1】:

考虑使用lambda expressions parser?您应该能够按照以下方式做一些事情:

[Verify("(Example e) => !e.Condition && e.Condition > 5")]
public void DoSomthing() 
{ ... }

然后使用以下代码编译:

[Serializable]
public class MyAspectAttribute : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionArgs args)
    {
         ExprParser parser = new ExprParser();
         LambdaExpression lambda = parser.Parse(/* Verify string comes here */);
         bool isConditionMet = (bool) parser.Run(lambda, this);

         if (isConditionMet)
         { ... }
    }
}

编辑:

对于自定义用户类型,您需要提供命名空间(如果类型驻留在与您调用解析器的程序集不同的程序集中,则需要提供程序集):

ExprParser.Using.Add("PersonTypeNamespace");
ExprParser parser = new ExprParser();
LambdaExpression lambda = parser.Parse("(Person p) => p.Name");
var output = parser.Run(lambda, new Person { Name = "DragonFire" });

download section 中有用户指南 文件 - 它提供了一些关于库使用的额外信息。

【讨论】:

  • +1 用于 lambda 解析器,但我仍然认为他应该避免使用魔法字符串作为条件。
  • 是的,这就是我要找的!谢谢!!
  • 我尝试使用它,但我有一个例外:当我解析“(e)=> e.Condition”字符串时出现“意外结束”......
  • @DragonFire:您需要添加命名空间/程序集名称 - 检查我的编辑。并且实际上使用完整的 lambda 表示法,例如。 (Example e) => ...
【解决方案2】:

一种会使调试变得困难的技术是使用#define 值。

例如,在其他一些项目中,您可以将CONDITION_5 声明为:

#define CONDITION_5

现在,在下面的示例类中,DoSomething() 是可见的。

public class Example
{

#if CONDITION_5
  public void DoSomthing()
  { ... }
#endif
}

如果您需要这些作为代码的变量,您可以在单独的类中定义公共变量来存储您的选择:

public static class Global {
  public static bool Condition_5 = true;
}

现在,在下面的示例类中,DoSomething() 始终可见,但除非您设置值,否则不会执行任何操作。

public class Example
{

  public void DoSomthing()
  {
    if (Global.Condition_5)
    {
      // do stuff
    }
  }
}

不过,和你一样,我希望看到一种更优雅的方法。

编辑:

正如我在第一条评论中指出的那样,OP 修改了他原来的问题。我的答案适合原始问题,而不是给出标记答案的问题。

【讨论】:

  • 好的,自从我开始写这个答案以来,很多 cmets。它可能不是你要找的东西,但我会把它留在这里稍微确定一下。
  • ??? #if CONDITION_5 将在编译时执行,并且该方法将永远不存在(或将永远存在)。这没有任何意义。
  • @ivowiblo:DragonFire 修改了他原来的问题,我在第一条评论中没有提及。我的回答与最初的问题相关,当然不值得你投反对票。
  • 哦!请将其添加到答案而不是评论中,以便我投票。
【解决方案3】:

您已经知道要使用的公式,因此只需将值传递给方面。

public class MyValidationAspect : OnMethodBoundaryAspect
{

public int Val1 { get; set; }
public int Val2 { get; set; }

public override void OnExit(MethodExecutionArgs args) 
    { 
        if (this.args.Arguments[0] > Val1) // If-statment from string, this is the problem... 
        { ... } 
    } 


}

[MyValidationAspect(Val1 = 5, Val2 = ...)]

不要试图变得如此通用/动态,只需制作一组具体的方面并根据需要传递值。

或者,您可以使用 Rosylen(编译器即服务)。

【讨论】:

  • 我必须使用不同的复杂条件......但是Rosylen......非常有趣!
  • @DragonFire 制作不止一个方面。尝试如此动态地执行此操作只会给您带来问题。我看不到条件会动态变化的用例。你要么做错了,要么正在努力偷懒。
【解决方案4】:

查看代码契约:http://research.microsoft.com/en-us/projects/contracts/ 如果自定义属性不是必须的,那么它们可能正是您所寻找的。

代码契约擅长定义方法的允许参数和返回值的约束,并有选择地在运行时(甚至编译时检查它们,尽管它确实会减慢 IDE)

【讨论】:

  • 我知道合同,但我的任务与软件验证无关...
【解决方案5】:

创建一组实现布尔逻辑的对象。

  • 等于比较器(采用属性名称和值)
  • 大于比较器(采用属性名称和值)
  • And Comparator(需要两个比较器)
  • 布尔求值器(取布尔属性的名称)
  • 等等等等

然后让您的属性将这些对象之一作为参数

[Verify(new AndComparator(
    new BooleanEvaluator ("Condition"), 
    new GreaterThanComparator("ConditionValue", 5)))]
public void DoSomthing()

【讨论】:

  • 我不能这样做,因为我可以使用嵌套属性,例如:[Verify("CurrentInfo.User.Account.IsValid")]
  • @DragonFire 当然可以,你只需要像Spring's Expression Evaluation这样的东西;即,您一边走一边走字符串 reflectioning 。另外,很酷的用户名。
【解决方案6】:

为什么不做这样的事情:

public class Example
{
  public Boolean Condition {get; set;}
  public Double ConditionValue {get; set;}


  public void DoSomthing()
  { 
           Verify.That(!Condition && ConditionValue>5);
           ...
  }
}

几乎相同数量的代码,它会在编译时被编译和验证,你将能够将东西放入配置中,验证私有成员并进行复杂的验证。

【讨论】:

  • 他正在寻找使用 AOP 为他编写条件。
  • 你是对的,这是他试图做的许多问题之一。
  • 我给出的答案大致相同。 AOP 是什么?
  • @jp2code - Aspect Oriented Programming。 PostSharp 只是可用于 .NET 的 AOP 工具包之一。
猜你喜欢
  • 2018-04-25
  • 1970-01-01
  • 2013-07-31
  • 2013-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-05
  • 2022-11-03
相关资源
最近更新 更多