这可能适用于其他地方,但在WinForms中,当我使用绑定时,我发现许多方法都希望将属性的名称绑定到。类似的东西:
class Person
{
public String Name { get { ... } set { ... } }
public int Age { get { ... } set { ... } }
}
class PersonView
{
void Bind(Person p)
{
nameControl.Bind(p,"Name");
ageControl.Bind(p,"Age");
}
}
我一直遇到的一个大问题是“Name”和“Age”被指定为字符串。这意味着如果有人重命名Person的一个属性,编译器就无济于事。代码编译正常,但绑定将被破坏。
我错过了解决这个问题的标准方法吗?感觉我需要一些关键字,也许叫做stringof来匹配现有的typeof。你可以使用它:
ageControl.Bind(p,stringof(p.Age).Name);
stringof可以返回一些具有获取完整路径,路径的一部分或字符串的属性的类,以便您自己解析它。
这样的事情已经可以吗?
答案 0 :(得分:4)
看看这个code snippet我发布了另一个问题,它可以帮到你! (但是,如果您使用的是.NET 3.5)
最诚挚的问候 Oliver Hanappi
答案 1 :(得分:4)
您可以使用表达式树来完成此操作,如in this question
所述protected static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression)
{
if (expression.NodeType == ExpressionType.Lambda && expression.Body.NodeType == ExpressionType.MemberAccess)
{
PropertyInfo prop = (expression.Body as MemberExpression).Member as PropertyInfo;
if (prop != null)
{
return prop.Name;
}
}
throw new ArgumentException("expression", "Not a property expression");
}
...
ageControl.Bind(p, GetPropertyName((Person p) => p.Age));
答案 2 :(得分:2)
您可以使用表达式来获取编译器检查的绑定。 例如,在当前的一个项目中,我们设置了这样的绑定:
DataBinder
.BindToObject(this)
.ObjectProperty(c => c.IsReadOnly)
.Control(nameTextBox, n => n.ReadOnly)
.Control(addressControl, n => n.ReadOnly)
支持此样式的代码分为几个类:
public static class DataBinder
{
public static DataBinderBindingSourceContext<TDataSource> BindToObject<TDataSource>(TDataSource dataSource)
{
return new DataBinderBindingSourceContext<TDataSource>(dataSource);
}
}
public class DataBinderBindingSourceContext<TDataSource>
{
public readonly object DataSource;
public DataBinderBindingSourceContext(object dataSource)
{
DataSource = dataSource;
}
public DataBinderControlContext<TDataSource, TProperty> ObjectProperty<TProperty>(Expression<Func<TDataSource, TProperty>> property)
{
return new DataBinderControlContext<TDataSource, TProperty>(this, property);
}
}
public class DataBinderControlContext<TDataSource, TProperty>
{
readonly DataBinderBindingSourceContext<TDataSource> BindingSourceContext;
readonly string ObjectProperty;
public DataBinderControlContext
(
DataBinderBindingSourceContext<TDataSource> bindingSourceContext,
Expression<Func<TDataSource, TProperty>> objectProperty
)
{
BindingSourceContext = RequireArg.NotNull(bindingSourceContext);
ObjectProperty = ExpressionHelper.GetPropertyName(objectProperty);
}
public DataBinderControlContext<TDataSource, TProperty> Control<TControl>(TControl control, Expression<Func<TControl, TProperty>> property)
where TControl : Control
{
var controlPropertyName = ExpressionHelper.GetPropertyName(property);
control.DataBindings.Add(controlPropertyName, BindingSourceContext.DataSource, ObjectProperty, true);
return this;
}
}
public static class ExpressionHelper
{
public static string GetPropertyName<TResult>(Expression<Func<TResult>> property)
{
return GetMemberNames(((LambdaExpression)property).Body).Skip(1).Join(".");
}
public static string GetPropertyName<T, TResult>(Expression<Func<T, TResult>> property)
{
return GetMemberNames(((LambdaExpression)property).Body).Join(".");
}
static IEnumerable<string> GetMemberNames(Expression expression)
{
if (expression is ConstantExpression || expression is ParameterExpression)
yield break;
var memberExpression = (MemberExpression)expression;
foreach (var memberName in GetMemberNames(memberExpression.Expression))
yield return memberName;
yield return memberExpression.Member.Name;
}
}
public static class StringExtentions
{
public static string Join(this IEnumerable<string> values, string separator)
{
if (values == null)
return null;
return string.Join(separator, values.ToArray());
}
}
答案 3 :(得分:0)
您可以使用反射来查找名称; - )
这当然是一个循环引用,你使用你认为它的名称来找到相同的名称(或者找不到任何东西,意味着该属性被重命名......但是有一个想法(或者更确切地说) ,一个技巧):通过对你想要使用的属性进行无操作引用,你会得到编译时间确认它仍然存在。唯一的问题是如果有人只是交换各种属性名称;在这种情况下,名称仍然存在(没有编译时错误),但具有不同的应用程序级语义(应用程序输出中可能出现意外)