0

考虑以下语句:

recorder.AddActivity(new Activity { ActivityName = "DeepSeaDiving", DayOfWeek = DayOfWeek.Monday });

取而代之的是,这里有一个帖子用于Expression Trees像这样进行花哨的调用:

 new WeeklyActivityRecorder () .WithActivities( Monday => "Lawn Moving",Tuesday => "Cooking");

我在这里看到了扩展方法,下面给出。

public static WeeklyActivityRecorder WithActivities(this WeeklyActivityRecorder recorder, params Expression<Func<DayOfWeek, string>>[] activityList) 
    {
    foreach (var activity in activityList)
                {
                    LambdaExpression expression = activity;
                    ConstantExpression enteredActivity = expression.Body as ConstantExpression;
                    DayOfWeek day = expression.Parameters[0];
                    recorder.AddActivity(new Activity{DayOfWeek = day, ActivityName = activity});
                }

                return recorder;
    }

但是,当我编译它时,编译器对扩展方法不满意,并抱怨 `Cannot convert sourceType ParameterExpression to DayOfWeek

上面使用的类的相关代码如下:

public class Activity
{
    /// <summary>
    /// Gets the activity name.
    /// </summary>
    public string ActivityName { get; set; }

    /// <summary>
    /// Gets The day of week.
    /// </summary>
    public DayOfWeek DayOfWeek { get; set; }
}

public class WeeklyActivityRecorder
{
    private List<Activity> Activities { get; set; }

    public WeeklyActivityRecorder()
    {

    }

    public List<Activity> GetAllActivities()
    {
        return this.Activities;
    }

    public void AddActivity(Activity activity)
    {
        if (this.Activities == null)
        {
            this.Activities = new List<Activity>();
        }

        if (activity != null)
        {
            this.Activities.Add(activity);
        }
    }
}

有什么想法我在这里想念的吗?

4

3 回答 3

3

那篇博文中的代码甚至都没有编译,我无论如何也不会使用它。表达式树会产生很大的开销,并且为此目的使用对象初始化器无论如何都更具可读性。

为什么它不起作用

当你写一个 lambda,即使是一个表达式,左边是 lambda 的参数——它们的类型和名称,而不是它们的值。因此MondayTuesday您的代码中只是参数名称的文字。编译器不会验证它们是有效的枚举成员。

更短的语法选项

使用Activity类的构造函数参数:

recorder.AddActivities(new Activity("DeepSeaDiving", DayOfWeek.Monday),
                       new Activity("Lawn Mowing", DayOfWeek.Tuesday));

您还可以为您的WeeklyActivityRecorder类使用集合初始化器:

class WeeklyActivityRecorder : IEnumerable
{
   public void Add(string name, DayOfWeek day) { ... }

   IEnumerator IEnumerable.GetEnumerator() { return Activities.GetEnumerator(); }
}

var recorder = new WeeklyActivityRecorder {
    { "DeepSeaDiving", DayOfWeek.Monday },
    { "Lawn Mowing", DayOfWeek.Tuesday} };
于 2013-10-21T09:42:58.457 回答
2

我不是 100% 确定那篇文章的目的是什么……但我感觉你做错了。

但是,您可以按照我认为您的意图让它工作:

DayOfWeek day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), activity.Parameters[0].Name);

您应该activity在每次迭代时存储参数名称。这会将其解析为枚举类型。

此外,您应该存储活动名称的表达式主体:

ActivityName = activity.Body.ToString()

允许这样做:

activityRecorder.WithActivities(Monday => "Something", Tuesday => "Something");

这非常hacky ..所以我肯定会重新考虑你想要做什么。如果您正在尝试创建表达式构建器(如文章所示),那么您应该只构建表达式并将它们直接传递给 NHibernate。

如果您不这样做..那么您应该真正考虑正确地处理表达式并决定要对它们做什么。

没有更多关于您希望最终将其用于什么的上下文。这是我能做的最好的事情(其他人可能有更好的想法。如果是这样的话,我会很乐意删除我的答案)。

于 2013-10-21T09:42:05.777 回答
1

您提供的代码在许多层面上都是错误的。

首先,在这一行中没有从 ParameterExpression 到 DayOfWeek 枚举的直接隐式转换:

DayOfWeek day = expression.Parameters[0];

这就是为什么你得到提到的编译器错误。

其次, WithActivities扩展方法的整个想法是错误的。您不能从表达式的参数中提取运行时信息。您传递的确切值是运行时信息。

第三,您不能使用所示的星期一星期二名称,除非它们是调用者类的成员。否则,它们只是参数的名称,您对它们没有任何智能支持。

因此,使用表达式树的全部意义超出了我的理解。一个接近的东西,不涉及表达式树,但提供一个流畅的界面,看起来像:

public static WeeklyActivityRecorder WithActivity(this WeeklyActivityRecorder recorder, DayOfWeek day, string activity)
{
    recorder.AddActivity(new Activity {ActivityName = activity, DayOfWeek = day});

    return recorder;
}

以及用法:

new WeeklyActivityRecorder()
    .WithActivity(DayOfWeek.Monday, "Lawn Moving")
    .WithActivity(DayOfWeek.Tuesday, "Cooking");
于 2013-10-21T09:51:57.657 回答