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

发布于 2024-10-28 00:13:37 字数 2717 浏览 1 评论 0原文

在我的上一个问题中, Linq 表达式和扩展方法来获取property name 我询问了使用表达式和扩展在两个 POCO 属性之间进行数据绑定的问题。我得到了一个有用的答案,它工作正常,但我有一个问题。

下面是代码:

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 => ID);而不是 x.Bind(Name => y.Id)。在这种情况下, 绑定失败,因为 目的地表达式.表达式是 常量表达式而不是 会员表达式。我不知道什么 我需要改变才能做到 在这种情况下工作。

  • 如果属性名称不正确,是否有办法使其在编译时失败,例如 x.Bind(Na123me => Id)?

In a previous question of mine, Linq expressions and extension methods to get property name I asked about data binding between two POCO properties using expressions and extensions. I got a helpful anser and it is working fine but I have a question about it.

Here is the code:

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);
    }
}

Usage:

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);
    }    
}

My questions regarding the above are:

  • When I make the call to Bind, the
    second parameter is a member of the
    current class, so I have something
    like x.Bind(Name =>
    Id); instead of x.Bind(Name => y.Id). In this case,
    the Bind fails since
    destinationExpression.Expression is a
    ConstantExpression instead of a
    MemberExpression. I am not sure what
    I would need to change to make it
    work in that case.

  • Is there a way to make it fail at compile time if a property name is incorrect, for example x.Bind(Na123me => Id)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鸩远一方 2024-11-04 00:13:37

不。事实是,您只是使用了一种技巧来更容易地生成这样的表达式。但无法强制 lambda 表达式在编译时遵循特定模式。这就是为什么像 LINQ to Entities 这样的技术往往会产生大量运行时异常。

No. The fact is, you're just using a trick to make it easier to produce an expression like this. But there is no way to enforce that the lambda expression follows a particular pattern at compile time. That's why technologies like LINQ to Entities tend to produce a lot of runtime exceptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文