有没有办法使C#binding静态工作?
这可能适用于其他地方,但在WinForms中,当我使用绑定时,我发现许多方法都希望使用要绑定到的属性的名称。比如:有没有办法使C#binding静态工作?,c#,language-features,C#,Language Features,这可能适用于其他地方,但在WinForms中,当我使用绑定时,我发现许多方法都希望使用要绑定到的属性的名称。比如: class Person { public String Name { get { ... } set { ... } } public int Age { get { ... } set { ... } } } class PersonView { void Bind(Person p) { nameControl.Bind(p,
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");
}
}
ageControl.Bind(p,stringof(p.Age).Name);
我一直面临的最大问题是“Name”和“Age”被指定为字符串。这意味着,如果有人重命名了Person的某个属性,编译器将毫无帮助。代码可以很好地编译,但是绑定会被破坏
有没有一个标准的方法来解决我错过的问题?我觉得我需要一些关键字,可能叫做stringof来匹配现有的typeof。您可以使用它,例如:
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");
}
}
ageControl.Bind(p,stringof(p.Age).Name);
stringof可以返回一些类,这些类具有获取完整路径、部分路径或字符串的属性,因此您可以自己解析它
这样的事情已经可以做了吗?您可以使用反射来查找名称;-) 这当然是一个循环引用,您可以使用您认为是的名称来查找相同的名称(或者不查找任何内容,这意味着该属性已重命名…但是有一个想法(或者更确切地说,是一个技巧):通过对希望使用的属性进行“不做任何事”引用,可以在编译时确认该属性仍然存在。唯一的问题是,如果有人只是交换各种属性名称;在这种情况下,名称仍然存在(没有编译时错误),但具有不同的应用程序级别语义(应用程序输出中可能出现的意外情况)看看我在另一个问题中发布的这个,它可以帮助您!(但只有在您使用.NET 3.5时) 致以最诚挚的问候
Oliver Hanappi如前所述,您可以通过表达式树实现这一点
受保护的静态字符串GetPropertyName(表达式)
{
if(expression.NodeType==ExpressionType.Lambda&&expression.Body.NodeType==ExpressionType.MemberAccess)
{
PropertyInfo prop=(expression.Body作为MemberExpression.Member作为PropertyInfo;
如果(prop!=null)
{
返回道具名称;
}
}
抛出新ArgumentException(“表达式”,“非属性表达式”);
}
...
绑定(p,GetPropertyName((Person p)=>p.Age));
您可以使用表达式来检查编译器绑定。
例如,在当前的一个项目中,我们设置了如下绑定:
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());
}
}
publicstaticclassdatabinder
{
公共静态DataBindinderBindingSourceContext BindToObject(TDataSource数据源)
{
返回新的DataBinderBindingSourceContext(数据源);
}
}
公共类DataBinderBindingSourceContext
{
公共只读对象数据源;
公共DataBinderBindingSourceContext(对象数据源)
{
数据源=数据源;
}
公共DataBinderControlContext对象属性(表达式属性)
{
返回新的DataBinderControlContext(此,属性);
}
}
公共类DataBinderControlContext
{
只读DataBinderBindingSourceContext BindingSourceContext;
只读字符串ObjectProperty;
公共DataBinderControlContext
(
DataBinderBindingSourceContext bindingSourceContext,
表达式对象属性
)
{
BindingSourceContext=RequireAG.NotNull(BindingSourceContext);
ObjectProperty=ExpressionHelper.GetPropertyName(ObjectProperty);
}
公共DataBinderControlContext控件(TControl控件,表达式属性)
其中TControl:Control
{
var controlPropertyName=ExpressionHelper.GetPropertyName(属性);
添加(controlPropertyName,BindingSourceContext.DataSource,ObjectProperty,true);
归还这个;
}
}
公共静态类ExpressionHelper
{
公共静态字符串GetPropertyName(表达式属性)
{
返回GetMemberNames(((LambdaExpression)属性).Body.Skip(1).Join(“.”);
}
公共静态字符串GetPropertyName(表达式属性)
{
返回GetMemberNames(((LambdaExpression)属性).Body.Join(“.”);
}
静态IEnumerable GetMemberName(表达式)
{
if(表达式为常量表达式| |表达式为参数表达式)
屈服断裂;
var memberExpression=(memberExpression)表达式;
foreach(GetMemberNames(memberExpression.Expression)中的var memberName)
产生返回成员名称;
yield返回memberExpression.Member.Name;
}
}
公共静态类StringExtensions
{
公共静态字符串联接(此IEnumerable值,字符串分隔符)
{
如果(值==null)
返回null;
返回string.Join(分隔符,values.ToArray());
}
}
这不是动态绑定那么多的C语言,这是WinForms.True。即使您不使用WinForms,这种语言功能也可能派上用场。