LINQ的EX pressions和扩展方法来获得属性名 [英] Linq expressions and extension methods to get property name

查看:291
本文介绍了LINQ的EX pressions和扩展方法来获得属性名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在看这个帖子,描述了一个简单的方法来做到POCO特性之间的数据绑定:数据绑定POCO属性

一个由贝文的评论包括,可用于实现这样的数据绑定的简单粘结剂类。它的工作原理非常适合我需要什么,但我想实现一些在贝文为改进课堂上,建议分别是:

  • 检查源和目标 分配
  • 检查属性 确定sourcePropertyName和 targetPropertyName存在
  • 检查类型的兼容性 这两个属性之间

此外,考虑到由字符串指定的属性是很容易出错,你可以使用LINQ的EX pressions和扩展方法代替。 ,而不是写那么

  Binder.Bind(来源:姓名,目标名称)
 

您可以写

  source.Bind(名称=> target.Name);
 

我是pretty的相信我能处理的前三个(尽管随意包括这些变化),但我不知道如何使用LINQ EX pressions和扩展方法,可以写code,而不使用属性名称的字符串。

任何提示?

下面是原来的code为链接找到:

 公共静态类粘合剂
{

    公共静态无效绑定(
        INotifyPropertyChanged的来源,
        串sourcePropertyName,
        INotifyPropertyChanged的目标,
        串targetPropertyName)
    {
        VAR sourceProperty
            = source.GetType()的getProperty(sourcePropertyName);
        VAR targetProperty
            = target.GetType()的getProperty(targetPropertyName);

        source.PropertyChanged + =
            (S,A)=>
            {
                VAR sourceValue = sourceProperty.GetValue(源,NULL);
                VAR targetValue = targetProperty.GetValue(目标,NULL);
                如果(!的Object.Equals(sourceValue,targetValue))
                {
                    targetProperty.SetValue(目标,sourceValue,NULL);
                }
            };

        target.PropertyChanged + =
            (S,A)=>
            {
                VAR sourceValue = sourceProperty.GetValue(源,NULL);
                VAR targetValue = targetProperty.GetValue(目标,NULL);
                如果(!的Object.Equals(sourceValue,targetValue))
                {
                    sourceProperty.SetValue(来源targetValue,NULL);
                }
            };
    }
}
 

解决方案

下面将返回一个属性名从一个lambda EX pression的字符串:

 公共字符串属性名< TProperty>(出pression< Func键< TProperty>>属性)
{
  VAR的λ=(LambdaEx pression)财产;

  MemberEx pression memberEx pression;
  如果(lambda.Body是UnaryEx pression)
  {
    VAR unaryEx pression =(UnaryEx pression)lambda.Body;
    memberEx pression =(MemberEx pression)unaryEx pression.Operand;
  }
  其他
  {
    memberEx pression =(MemberEx pression)lambda.Body;
  }

  返回memberEx pression.Member.Name;
}
 

用法:

 公共类MyClass的
{
  公众诠释世界{获得;组; }
}

...
变种C =新MyClass的();
Console.WriteLine(你好{0},属性名(()=> c.World));
 

更新

 公共静态类扩展
{
    公共静态无效绑定< TSourceProperty,TDestinationProperty>(这INotifyPropertyChanged的来源,例pression< Func键< TSourceProperty,TDestinationProperty>> bindEx pression)
    {
        VAR EX pressionDetails = GETEX pressionDetails< TSourceProperty,TDestinationProperty>(bindEx pression);
        VAR sourcePropertyName = EX pressionDetails.Item1;
        VAR destinationObject = EX pressionDetails.Item2;
        VAR destinationPropertyName = EX pressionDetails.Item3;

        //不要绑定在这里
        Console.WriteLine({0} {1},sourcePropertyName,destinationPropertyName);
    }

    私有静态元组LT;字符串,INotifyPropertyChanged的,串> GETEX pressionDetails< TSourceProperty,TDestinationProperty>(出pression< Func键< TSourceProperty,TDestinationProperty>> bindEx pression)
    {
        VAR的λ=(LambdaEx pression)bindEx pression;

        ParameterEx pression sourceEx pression = lambda.Parameters.FirstOrDefault();
        MemberEx pression destinationEx pression =(MemberEx pression)lambda.Body;

        VAR memberEx pression = destinationEx pression.Ex pression为MemberEx pression;
        VAR constantEx pression = memberEx pression.Ex pression为ConstantEx pression;
        VAR字段信息= memberEx pression.Member的字段信息;
        VAR destinationObject = fieldInfo.GetValue(constantEx pression.Value)为INotifyPropertyChanged的;

        返回新行<字符串,INotifyPropertyChanged的,串>(sourceEx pression.Name,destinationObject,destinationEx pression.Member.Name);
    }
}
 

用法:

 公共类TestSource:INotifyPropertyChanged的
{
    公共事件PropertyChangedEventHandler的PropertyChanged;

    公共字符串名称{;组; }
}

公共类TestDestination:INotifyPropertyChanged的
{
    公共事件PropertyChangedEventHandler的PropertyChanged;

    公共字符串ID {获得;组; }
}

类节目
{
    静态无效的主要(字串[] args)
    {
        VAR X =新TestSource();
        变种Y =新TestDestination();

        x.Bind<字符串,字符串>(名称=> y.Id);
    }
}
 

I was looking at this post that describes a simple way to do databinding between POCO properties: Data Binding POCO Properties

One of the comments by Bevan included a simple Binder class that can be used to accomplish such data binding. It works great for what I need but I would like to implement some of the suggestions that Bevan made to improve the class, namely:

  • Checking that source and target are assigned
  • Checking that the properties identified by sourcePropertyName and targetPropertyName exist
  • Checking for type compatibility between the two properties

Also, given that specifying properties by string is error prone, you could use Linq expressions and extension methods instead. Then instead of writing

Binder.Bind( source, "Name", target, "Name")

you could write

source.Bind( Name => target.Name);

I'm pretty sure I can handle the first three (though feel free to include those changes) but I have no clue how to use Linq expressions and extension methods to be able to write code without using property name strings.

Any tips?

Here is the original code as found in the link:

public static class Binder
{

    public static void Bind(
        INotifyPropertyChanged source,
        string sourcePropertyName,
        INotifyPropertyChanged target,
        string targetPropertyName)
    {
        var sourceProperty
            = source.GetType().GetProperty(sourcePropertyName);
        var targetProperty
            = target.GetType().GetProperty(targetPropertyName);

        source.PropertyChanged +=
            (s, a) =>
            {
                var sourceValue = sourceProperty.GetValue(source, null);
                var targetValue = targetProperty.GetValue(target, null);
                if (!Object.Equals(sourceValue, targetValue))
                {
                    targetProperty.SetValue(target, sourceValue, null);
                }
            };

        target.PropertyChanged +=
            (s, a) =>
            {
                var sourceValue = sourceProperty.GetValue(source, null);
                var targetValue = targetProperty.GetValue(target, null);
                if (!Object.Equals(sourceValue, targetValue))
                {
                    sourceProperty.SetValue(source, targetValue, null);
                }
            };
    }
}

解决方案

The following will return a property name as a string from a lambda expression:

public string PropertyName<TProperty>(Expression<Func<TProperty>> property)
{
  var lambda = (LambdaExpression)property;

  MemberExpression memberExpression;
  if (lambda.Body is UnaryExpression)
  {
    var unaryExpression = (UnaryExpression)lambda.Body;
    memberExpression = (MemberExpression)unaryExpression.Operand;
  }
  else
  {
    memberExpression = (MemberExpression)lambda.Body;
  }

  return memberExpression.Member.Name;
}

Usage:

public class MyClass
{
  public int World { get; set; }
}

...
var c = new MyClass();
Console.WriteLine("Hello {0}", PropertyName(() => c.World));

UPDATE

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

这篇关于LINQ的EX pressions和扩展方法来获得属性名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆