简化泛型扩展方法

本文关键字:方法 扩展 泛型 | 更新日期: 2023-09-27 18:15:32

我已经编写了一个通用的扩展方法,它基本上添加了一个绑定到windows窗体ui元素(如窗体或按钮)。

它现在工作得很好,在一些项目中尝试过,但是它仍然是一个相当复杂的方法,有3个通用的"t参数"。

public static void Add<T1, T2, T3>(
    this ControlBindingsCollection collection,
    T2 dataSrc,
    Expression<Func<T1, T3>> p1,
    Expression<Func<T2, T3>> p2)
    where T1 : class 
    where T2 : class 
{
    var prop1Name = PropertyNameResolver.GetPropertyName(p1);
    var prop2Name = PropertyNameResolver.GetPropertyName(p2);
    collection.Add(prop1Name, dataSrc, prop2Name, false, DataSourceUpdateMode.OnPropertyChanged);
}

GetPropertyName看起来像这样:

public static string GetPropertyName<T1,T2>(Expression<Func<T1,T2>> propertyExpression)
{
    return ((MemberExpression)propertyExpression.Body).Member.Name;
}
下面是我如何调用方法的两个例子:
DataBindings.Add<Form, FrmOptionsPresenter, double>(
    m_frmOptionsPresenter,
    binder => binder.Opacity,
    dataSrc => dataSrc.Opacity);

就像我上面说的,这个调用看起来有点重。

我现在想知道的是:有什么你可以建议我使这些方法更简单和可读的吗?

提前感谢!

简化泛型扩展方法

看看我们的实现:

public static class BindableComponentExtensions
{
    public static void Bind<T>(this IBindableComponent component, T value, Expression<Func<object>> controlProperty, Expression<Func<T, object>> modelProperty)
        where T : INotifyPropertyChanged
    {
        component.DataBindings.Add(new Binding(
            StringExtensions.PropertyName(controlProperty),
            value,
            StringExtensions.PropertyName(modelProperty),
            true,
            DataSourceUpdateMode.OnPropertyChanged));
    }
    public static void Bind<TComponent, T>(this TComponent component, T value,
        Expression<Func<TComponent, object>> controlProperty, Expression<Func<T, object>> modelProperty)
        where TComponent : IBindableComponent
        where T : INotifyPropertyChanged
    {
        component.DataBindings.Add(new Binding(
            StringExtensions.PropertyName(controlProperty),
            value,
            StringExtensions.PropertyName(modelProperty),
            true,
            DataSourceUpdateMode.OnPropertyChanged));
    }
    public static void OneWayBind<TComponent, T>(
        this TComponent component, T value, 
        Expression<Func<TComponent, object>> controlProperty, 
        Expression<Func<T, object>> modelProperty
    )
        where TComponent : IBindableComponent
        where T : INotifyPropertyChanged
    {
        component.DataBindings.Add(new Binding(
            StringExtensions.PropertyName(controlProperty),
            value,
            StringExtensions.PropertyName(modelProperty),
            true,
            DataSourceUpdateMode.Never));
    }
}

和用法:

combobox.Bind(name, c => c.SelectedValueId, v => v.OrganizationLegalFormId);
_auditName.OneWayBind(_model, c => c.Text, v => v.DisplayName);

其中name_model为数据模型类,c => c.SelectedValueIdc => c.Text为控制属性,v => v.DisplayNamev => v.OrganizationLegalFormId为模型属性。

StringExtensions.PropertyName是你的PropertyNameResolver.GetPropertyName:

public static class StringExtensions
{
    public static string MethodName<T>(Expression<Action<T>> action)
    {
        return ReflectionExtensions.GetMethodInfo(action).Name;
    }
    public static string PropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertyExpression)
    {
        return PropertyNameInternal(propertyExpression);
    }
    public static string PropertyName<T>(Expression<Func<T>> propertyExpression)
    {
        return PropertyNameInternal(propertyExpression);
    }
    private static string PropertyNameInternal(LambdaExpression propertyExpression)
    {
        if (propertyExpression == null)
            throw new ArgumentNullException(@"propertyExpression");
        var memberExpression = propertyExpression.Body as MemberExpression;
        if (memberExpression == null)
        {
            var ubody = (UnaryExpression)propertyExpression.Body;
            memberExpression = ubody.Operand as MemberExpression;
        }
        if (memberExpression == null)
            throw new ArgumentException(@"The expression is not a member access expression.", @"propertyExpression");
        var property = memberExpression.Member as PropertyInfo;
        if (property == null)
            throw new ArgumentException(@"The member access expression does not access a property.", @"propertyExpression");

        return memberExpression.Member.Name;
    }
}