对特定类型的类属性执行操作

时间:2015-03-01 10:28:43

标签: c# reflection

问题

例如,假设您收到一个具有许多属性的对象,其中一些属性是字符串。它甚至可能是包含任意级别的嵌套对象的对象,但为了简单起见,请将其保持平整。

public class Foo
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public int Prop3 { get; set; }
    public string PropN { get; set; }
}

您希望确保在传递此对象之前从string类型的属性中删除所有“#”字符。接下来发生的事情超出了问题的范围,但它可能存储在数据库中,通过网络发送,写入文件等。

一种简单的方法

一种方法(当前正在使用的方法)是使用一种方法来纠正每个字符串属性:

foo.Prop1 = RemoveUnwantedCharacters( foo.Prop1 );
foo.Prop2 = RemoveUnwantedCharacters( foo.Prop2 );
//etc

问题在于每当向Foo添加新属性时,都需要扩展此代码。将新属性添加到Foo的人很可能会忘记删除不需要的字符。

使用反射

所以,我正在考虑使用反射来解析对象上的属性并根据需要进行更正。我很少在生产代码中使用反射(我一直在测试代码中使用它),因为通常有一种更简单,更易理解的方法,并且由于一些性能问题(大多数都没有根据)。我想到的方法类型的一个例子是:

    static void Main()
    {
        var foo = new Foo {Prop1 = "Prop1#", Prop2 = "Pr#op2", Prop3 = 12, PropN = "#Pro#pN#"};
        DoSomething(foo);
    }

    static void DoSomething( Foo foo )
    {
        RemoveUnwantedCharacters( foo );
    }

    static void RemoveUnwantedCharacters( Foo foo )
    {
        var stringProps =
            foo.GetType()
                .GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly )
                .Where( p => p.PropertyType == typeof( string ) ).ToList();
        if( stringProps.Any() )
        {
            foreach( var stringProp in stringProps )
            {
                var currentValue = stringProp.GetValue( foo ).ToString();
                stringProp.SetValue( foo, currentValue.Replace( "#", string.Empty ) );
            }
        }
    }

反思是正确的选择吗?

虽然我很欣赏有关上述代码改进的建议,但它只是一个一次性的例子,我更感兴趣的是反射是否是一种好方法。

代码从所有字符串中删除#。这种方法的好处是无论何时向Foo添加新字符串,都会删除不需要的字符 - 没有什么必须改变。

除了性能之外,如果有更直观/更优雅的方式,我感兴趣。

我想有一个论点是,如果有一个字符串属性我们不想从中删除不需要的字符,那么这种方法就不会按原样运行。在我的情况下,没有,但只是为了争论,如果有一个选项是添加属性,如我们在反射解析中检查的[RemoveUnwantedCharacters]。这似乎仍然比上面列出的第一个选项更好,因为规则随属性一起添加,通过查看属性而不是在其他方法中,显而易见的是验证是什么。但是,它确实存在添加新属性的人只是忘记添加属性的风险。

此示例显示了一个字符串,但是有类似的情况用于更正整数(例如,如果int属性的值大于1000,则将其设置为1000,等于类的所有int属性)等。

所以,总结一下: -

  1. 这是否适合使用反射?
  2. 是否有更好的方法(例如,在不支持内省的C ++等语言中这样做的好方法)?

1 个答案:

答案 0 :(得分:1)

我个人喜欢反思方法。它为该功能提供了一个奇异的接触点(入口)。

其他选项是将转换函数插入属性的setter或getter。它具有与您提出的属性问题相同的优点和缺点 - 有一个重要的例外:您丢失了该功能的单一入口点。

AOP也可能在这种情况下有所帮助 - 但是我不能胜任这项技术。

无论你选择哪种方式,你的测试用例都应该让任何健忘的程序员都知道。