2

英语不是我的母语,我希望我能让我的问题足够清楚。

我想知道在执行时如何识别 Action 类中包含哪些操作(准确地说,将调用哪些属性)。

想象一个简单的 Employee 类......

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

...以及一个以 Action<> 作为参数的简单 Update() 方法

public static void Update(Action<Employee> action) {
    //HERE : how could i know which properties will be assigned by analyzing the Action<Employee> object ?

    Employee em = new Employee();

    action(em);

    //Only FirstName and LastName have been assigned to "em"
}

Update 方法可以这样调用:

//Call the Update method with only two "actions" : assign FirstName and LastName properties.
Update(e => { e.FirstName = "firstname"; e.LastName = "lastname"; });

我的问题是在 Update() 方法中确定哪些属性已“计划”用于 Action<> 对象中的赋值(以及相关值)。

通过分析 Action<> 对象,我如何发现只有属性 FirstName 和 LastName 将被分配值 "firstname" 和 "lastname" ?有可能吗?

我在谷歌和 SO 上找不到任何帮助。也许我以错误的方式问这个问题。

消息的末尾是可以执行/调试的整个程序。

在此先感谢这里的所有人。

麦克风

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestAction
{
    class Program
    {
        public class Employee
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Age { get; set; }
            public string Email { get; set; }
        }

        static void Main(string[] args)
        {
            //Call the Update method with only two "actions" : assign FirstName and LastName properties.
            Update(e => { e.FirstName = "firstname"; e.LastName = "lastname"; });
        }

        public static void Update(Action<Employee> action)
        {
            //HERE : how could i know which properties will be assigned by analyzing the Action<Employee> object ?

            Employee em = new Employee();

            action(em);

            //Only FirstName and LastName have been assigned to "em"
        }
    }
}
4

4 回答 4

1

感谢大家让我意识到无法分析代表(如果没有您的解释,我仍然会试图弄清楚如何......)。

为了实现我想要做的事情,我需要传递属性分配列表的可能性,以及分析该列表的可能性。在您的帮助下,我得出结论,只能分析表达式树。我是这样做的:

public static void Update<T>(Expression<Action<T>> action) where T : class

在 Update 方法中,使用标准的访问者模式分析表达式:我能够获取分配的属性和关联的值。

该方法是这样调用的:

Update<Employee>(o => new Employee() { FirstName = "Mike", Email = "mike@so.com" });

再次感谢你的帮助 !

麦克风

于 2013-06-28T16:58:29.513 回答
1

这不是一个容易解决的问题,但让我概述一下知道如何做到这一点的方法,如果你真的需要这样做的话。

拆解解读

这将涉及获取一个 .NET(或 x86/x64)反汇编程序,您将在运行时运行该反汇编程序,将其指向有问题的方法,然后分析输出,寻找对目标类型字段的访问。

我会说这很困难,您需要对 MSIL 以及编译器采用的可能的优化技术有很好的理解,以便从该技术中获得您想要的东西。

使用记录访问的代理对象

您可以创建一个代理对象,将其传递给操作委托。这个代理对象可能会在每个属性的布尔变量中记录每个属性被访问过。然后,您将查看这些布尔值以确定访问了哪些属性。

这更容易做到,你需要让你的类是虚拟的,每个属性也是虚拟的,然后创建一个后代类,你可以使用 Reflection.Emit 或其他方式在运行时创建类型。

但是,它要求您实际执行操作委托所针对的方法中的所有代码,这可能是不需要的。

您还可以使用原始对象的常规副本,给每个属性一些您知道操作委托不会给它的魔法值,调用委托,并检查魔法值和当前值之间的差异(通话后)。不幸的是,这还需要您调用委托,并且还会在目标对象上执行任何属性设置器,这两者都可能是不需要的。

我的意见

在我看来,你最好找到一种不同的方法来做到这一点,这更明确。

于 2013-06-28T07:38:08.963 回答
1

您无法以某种内置方式查看更改的内容,因为更改的内容与实例的当前状态有关。例子:

A {Name="Patrick"} //init 
A {Name = "Jane"} // changed from Patrick to Jane
A {Name = "Martin"} //changed from Jane to Martin

所以我没有其他方法可以自己管理。跟踪所有属性设置器,当其中一个是set调用者时,将更改的属性名称放入对象列表实例的某个本地。

Update调用时,滚动更改属性的名称列表,仅获取它们的值并更新它们(全部通过反射)。更新成功后,清理列表。

只是一个想法,但也可能有其他方法可以实现这一目标。

于 2013-06-28T07:38:16.797 回答
0

您无法分析代表。要进行分析,您需要一个表达式树:

public static void Update(Expression<Action<Employee>> action)

不幸的是,编译器无法自动将带有主体的 lambda 表达式转换为表达式树,因此您需要将表达式限制为每次调用的一个属性。
此外,带有赋值运算符的表达式树也不能自动转换,因此您必须找到其他方法。

于 2013-06-28T07:37:58.213 回答