关于C#表达式树的建议

时间:2008-10-01 01:00:42

标签: c# reflection expression-trees

我正在研究一种接受表达式树作为参数的方法,以及类的类型(或实例)。

基本思想是,此方法会将某些内容添加到将用于验证的集合中。

public interface ITestInterface
{
    //Specify stuff here.
}

private static void DoSomething<T>(Expression<Func<T, object>> expression, params IMyInterface[] rule)
{
    // Stuff is done here.
}

该方法调用如下:

class TestClass
{
    public int MyProperty { get; set; }
}

class OtherTestClass  : ITestInterface
{
    // Blah Blah Blah.
}

static void Main(string[] args)
{
    DoSomething<TestClass>(t => t.MyProperty, 
        new OtherTestClass());
}

我这样做是因为我希望传入的属性名称是强类型的。

我正在努力的一些事情......

  1. 在DoSomething中,我想获得T的PropertyInfo类型(来自传入的正文)并将其与rule []一起添加到集合中。目前,我正在考虑使用expression.Body并从“转换。([propertyname])”中删除[propertyname]并使用反射来获取我需要的东西。这看起来既麻烦又错误。还有更好的方法吗?
  2. 这是我正在使用的特定模式吗?
  3. 最后,对于我对我正在做的事情的误解和/或C#表达树上的资源或良好信息的任何建议或澄清也会受到赞赏。
  4. 谢谢!

    伊恩

    编辑:

    在DoSomething方法中返回expression.Body.ToString()的示例是一个字符串,如果从上面的示例调用,则包含“Convert(t.MyProperty)”。

    我确实需要它是强类型的,所以如果我更改属性名称它将无法编译。

    感谢您的建议!

3 个答案:

答案 0 :(得分:3)

我非常依赖表达式树来将我当前应用程序的许多内容推送到编译时,即静态类型检查。

我遍历表达式树,将它们翻译成“有意义”的其他东西。

我最终做的很多事情是,我依赖于一种MVC方式而不是URL,我在这种方法中声明了lambda函数,并将其转换为...,将编译器生成的表达式树转换为URL。调用此URL时,我会执行相反的操作。通过这种方式,我将所谓的编译时检查称为断开链接,这也适用于重构和重载。我认为以这种方式考虑使用表达式树是很酷的。

你可能想看一下访问者模式,开始时很难,因为它在开始时没有多大意义,但它将所有内容联系在一起,这是解决编译器构造中类型检查的一种非常正式的方法。你可以这样做,但不是类型检查发出你需要的东西。

我目前正在抨击的是能够构建一个简单的框架来翻译(或实际上我应该说是解释)表达式tress并发出JavaScript。我们的想法是编译器生成的表达式树将转换为与某些对象模型接口的有效JavaScript。

令人兴奋的是,当我出错时,编译器始终能够告诉我并确定最终结果只是一堆字符串,但重要的部分是如何创建这些字符串。他们经过了一些验证,这意味着什么。

一旦你实现这一目标,你几乎无法用表达树做到这一点。

在使用System.Reflection.Emit时,我发现自己使用表达式树来为动态编译创建一个轻量级框架,在编译时基本上可以说我的动态创建的程序集是否也可以编译,这样就可以了与反射和静态类型检查无缝对接。它进一步采取了这一点,并最终得到了一些东西,最终节省了大量的时间,并证明是非常灵活和强大。

所以我喜欢这种东西,这就是元编程的全部内容,在程序中编写程序。我说保持它的到来!

答案 1 :(得分:2)

从Expression.Body收集PropertyInfo对象与另一个问题的my solution类似。

答案 2 :(得分:2)

我很欣赏你在这里尝试做什么。我遇到了这个难题。写作总是感觉很奇怪:

DoSomething("MyProperty", new OtherClass());

如果属性更改了名称,或者调用中的文本输入错误,则会出现问题。我要学习的是,这可能是您可能需要通过测试来处理的。具体来说,单元测试。我会编写单元测试来强制“DoSomething”调用正常工作。

您可能尝试的另一件事是使用属性修饰属性,然后在构造时查找具有该属性的属性并加载规则。

[DoSomething(typeof(OtherClass), typeof(OtherClass2))]
public int MyProperty
{
  get;
  set;
}

在这种情况下,构造函数(可能在基类?中)将动态创建OtherClass对象和OtherClass2对象,并将它们与属性的名称一起加载到集合中。