在lambda表达式中在编译时检查属性名称

时间:2011-03-31 20:03:59

标签: c# .net data-binding poco system.componentmodel

在我之前的一个问题Linq expressions and extension methods to get property name中,我询问了使用表达式和扩展的两个POCO属性之间的数据绑定。我得到了一个有用的anser,它工作正常,但我有一个问题。

以下是代码:

public static class Extensions
{
    public static void Bind<TSourceProperty, TDestinationProperty>(this INotifyPropertyChanged source, Expression<Func<TSourceProperty, TDestinationProperty>> bindExpression)
    {
        var expressionDetails = GetExpressionDetails<TSourceProperty, TDestinationProperty>(bindExpression);
        var sourcePropertyName = expressionDetails.Item1;
        var destinationObject = expressionDetails.Item2;
        var destinationPropertyName = expressionDetails.Item3;

        // Do binding here
        Console.WriteLine("{0} {1}", sourcePropertyName, destinationPropertyName);
    }

    private static Tuple<string, INotifyPropertyChanged, string> GetExpressionDetails<TSourceProperty, TDestinationProperty>(Expression<Func<TSourceProperty, TDestinationProperty>> bindExpression)
    {
        var lambda = (LambdaExpression)bindExpression;

        ParameterExpression sourceExpression = lambda.Parameters.FirstOrDefault();
        MemberExpression destinationExpression = (MemberExpression)lambda.Body;

        var memberExpression = destinationExpression.Expression as MemberExpression;
        var constantExpression = memberExpression.Expression as ConstantExpression;
        var fieldInfo = memberExpression.Member as FieldInfo;
        var destinationObject = fieldInfo.GetValue(constantExpression.Value) as INotifyPropertyChanged;

        return new Tuple<string, INotifyPropertyChanged, string>(sourceExpression.Name, destinationObject, destinationExpression.Member.Name);
    }
}

用法:

public class TestSource : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Name { get; set; }        
}

public class TestDestination : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Id { get; set; }    
}

class Program
{        
    static void Main(string[] args)
    {
        var x = new TestSource();
        var y = new TestDestination();

        x.Bind<string, string>(Name => y.Id);
    }    
}

我对上述问题的疑问是:

  • 当我打电话给Bind时, 第二个参数是一个成员 当前的课程,所以我有一些东西 像x.Bind(Name =&gt; ID);而不是x.Bind(Name =&gt; y.Id)。在这种情况下, Bind失败了 destinationExpression.Expression是一个 ConstantExpression而不是 MemberExpression。我不确定是什么 我需要改变才能做到 在那种情况下工作。

  • 如果属性名称不正确,有没有办法让它在编译时失败,例如x.Bind(Na123me =&gt; Id)?

1 个答案:

答案 0 :(得分:0)

没有。事实是,你只是使用一个技巧,以便更容易生成这样的表达式。但是没有办法强制lambda表达式在编译时遵循特定模式。这就是为什么像LINQ to Entities这样的技术往往会产生大量的运行时异常。