如何重写此代码块?

时间:2013-08-13 11:53:51

标签: c# refactoring

我有一个有大约40个属性的类(我没有说这个,它是按照规范)。所有属性都有自定义“设置”方法。

我必须对所有“set”方法强加一点复杂的验证。我已经将验证分成了一个单独的方法,让我们调用它

CommonValidate(string PropertyName, string PropertyValue)

截至目前,我正在从每个“set”方法中调用此验证方法,如下所示:

    public string Property1
    {
        set 
        { 
           this.field1 = value; 
           CommonValidate(Property1, this.field1);
        }
     }

    public DateTime Property2
    {
        set 
        { 
           this.field2 = value.ToString("ddMMyy");; 
           CommonValidate(Property2, this.field2);
        }
     }

     public string Property3
    {
        set 
        { 
           this.field3 = value; 
           CommonValidate(Property3, this.field3);
        }
     }

这样我只是在所有40个“set”方法中粘贴了CommonValidate方法。 我发现这是非常无效的,想象一下如果CommonValidate方法中的参数数量有变更请求。

还有其他方法可以将其更改为更好的模式吗?

2 个答案:

答案 0 :(得分:1)

您可以使用反射来传递您在属性名称和新值中传递的函数。它进行验证,然后使用值执行正常设置。反射在速度方面效率不高,但对于重用代码非常有用。做一些诊断以确保时间丢失在可接受的范围内。

void ValidateAndSet(string propName, object newValue){
    foreach(var prop in propsClass.GetType().GetProperties().Where(p => p.Name == propName))
    {
        if(CommonValidate(prop, newValue))
            prop.GetSetMethod().Invoke(propsClass, new object[] { newValue});
        return; // Only one anyways
    }
    Logger.Log("Failed to find the property '{0}' to set '{1}'", propName, newValue);
}

propsClass是属性所在的类对象。可以在类中执行此操作,也可以将其作为另一个参数传递给函数。

答案 1 :(得分:0)

有人已经提到动态类,我对它们并不熟悉,但简短的阅读使它们对你的问题听起来很有吸引力。

但是,如果你不走这条路,我要改变的一件事就是在CommonValidate中使用字符串,而是使用System.Linq.Expression

我重写它看起来像:

static void CommonValidate<T>(Expression<Func<MyClass, T>> propertySelector, T newValue) //replace MyClass with name of current class
{
    MemberExpression memberExpression = propertySelector.Body as MemberExpression;
    if (memberExpression == null)
        throw new ArgumentException("propertySelector")

    string propertyName = MemberExpression.Member.Name;

    //validation code, e.g.

    CommonValidate(propertyName, newValue.ToString())
}

然后,setter看起来像

public string Property1
{
    set 
    { 
       this.field1 = value; 
       CommonValidate(c => c.Property1, value);
    }
 }

这样做的好处是,如果更改类上属性的名称,则编译时错误不会更改CommonValidate调用。如果你选择了这条路线,你应该使用类似的东西设置你的验证:我假设你有一个构造函数在某处填充Dictionary<string, Func<string, bool> - 使用类似于新CommonValidate的代码以上获取属性名称键。