gpt4 book ai didi

c# - 获取属性名称的 Linq 表达式和扩展方法

转载 作者:太空狗 更新时间:2023-10-30 00:08:52 24 4
gpt4 key购买 nike

我正在看这篇描述在 POCO 属性之间进行数据绑定(bind)的简单方法的帖子:Data Binding POCO Properties

Bevan 的评论之一包含一个简单的 Binder 类,可用于完成此类数据绑定(bind)。它非常适合我的需要,但我想实现 Bevan 提出的一些改进类(class)的建议,即:

  • 检查源和目标是分配
  • 检查属性由 sourcePropertyName 和targetPropertyName存在
  • 检查类型兼容性在两个属性之间

此外,鉴于通过字符串指定属性很容易出错,您可以改用 Linq 表达式和扩展方法。然后而不是写

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

你可以写

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

我很确定我可以处理前三个(尽管可以随意包含这些更改)但我不知道如何使用 Linq 表达式和扩展方法来编写代码而不使用属性名称字符串。

有什么建议吗?

这是在链接中找到的原始代码:

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

最佳答案

以下将从 lambda 表达式返回属性名称作为字符串:

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

用法:

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

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

更新

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

关于c# - 获取属性名称的 Linq 表达式和扩展方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5252176/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com