问题
例如,假设您收到一个具有许多属性的对象,其中一些属性是字符串。它甚至可能是包含任意级别的嵌套对象的对象,但为了简单起见,请将其保持平整。
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属性)等。
所以,总结一下: -
答案 0 :(得分:1)
我个人喜欢反思方法。它为该功能提供了一个奇异的接触点(入口)。
其他选项是将转换函数插入属性的setter或getter。它具有与您提出的属性问题相同的优点和缺点 - 有一个重要的例外:您丢失了该功能的单一入口点。
AOP也可能在这种情况下有所帮助 - 但是我不能胜任这项技术。
无论你选择哪种方式,你的测试用例都应该让任何健忘的程序员都知道。