我有多个大型对象,每个对象都有大约60个字符串。 我必须修剪所有这些字符串,并且我希望能够自动地使每个对象发现其自己的字符串并执行操作,而不必使用“this.mystring = this.mystring.Trim()”。
我知道一些关于反射的知识,但还不够,但我认为这是可能的?
另外,我不确定是否重要,但是一些字符串属性是只读的(只有getter),因此这些属性必须被跳过。
请帮忙?
我有多个大型对象,每个对象都有大约60个字符串。 我必须修剪所有这些字符串,并且我希望能够自动地使每个对象发现其自己的字符串并执行操作,而不必使用“this.mystring = this.mystring.Trim()”。
我知道一些关于反射的知识,但还不够,但我认为这是可能的?
另外,我不确定是否重要,但是一些字符串属性是只读的(只有getter),因此这些属性必须被跳过。
请帮忙?
获取所有属性并找出其中字符串类型和可写的属性很容易。使用LINQ可以更加简单。
var props = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
// Ignore non-string properties
.Where(prop => prop.PropertyType == typeof(string))
// Ignore indexers
.Where(prop => prop.GetIndexParameters().Length == 0)
// Must be both readable and writable
.Where(prop => prop.CanWrite && prop.CanRead);
foreach (PropertyInfo prop in props)
{
string value = (string) prop.GetValue(instance, null);
if (value != null)
{
value = value.Trim();
prop.SetValue(instance, value, null);
}
}
如果修剪实际上没有任何区别,您可能只想在需要时设置属性,以避免对于复杂的属性进行冗余计算-或者这可能对您没有影响。
如果有必要,有各种改善性能的方法,例如:
Delegate.CreateDelegate
来构建获取器和设置器的委托除非性能真正成为问题,否则不建议采取任何这些措施。
Something like:
foreach (PropertyInfo prop in obj.GetType().GetProperties(
BindingFlags.Instance | BindingFlags.Public))
{
if (prop.CanRead && prop.CanWrite && prop.PropertyType == typeof(string)
&& (prop.GetIndexParameters().Length == 0)) // watch for indexers!
{
var s = (string)prop.GetValue(obj, null);
if (!string.IsNullOrEmpty(s)) s = s.Trim();
prop.SetValue(obj, s, null);
}
}
Type.GetProperties()
调用包括静态属性,我怀疑这里不应该包括它们。 - Jon SkeetIsReadable
;p 另外 - 你可能想检查索引器。 - Marc Gravellpublic string this[int i] {get {...} set {...}}
,它作为一种特殊类型的属性出现。 - Marc Gravell在 props 循环中不需要检查 IEnumerable
,如果实际实例是 IEnumerable
,则忽略 props。针对 IEnumerable
的修复:
private void TrimWhitespace(object instance)
{
if (instance != null)
{
if (instance is IEnumerable)
{
foreach (var item in (IEnumerable)instance)
{
TrimWhitespace(item);
}
}
var props = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
// Ignore indexers
.Where(prop => prop.GetIndexParameters().Length == 0)
// Must be both readable and writable
.Where(prop => prop.CanWrite && prop.CanRead);
foreach (PropertyInfo prop in props)
{
if (prop.GetValue(instance, null) is string)
{
string value = (string)prop.GetValue(instance, null);
if (value != null)
{
value = value.Trim();
prop.SetValue(instance, value, null);
}
}
else
TrimWhitespace(prop.GetValue(instance, null));
}
}
}
稍微扩展一下,我有一个包含列表的复杂对象,我想遍历它并修剪所有子字符串对象。这是我根据@Jon答案所构建的代码。如果有更好的方法或者我错过了什么明显的东西,我很好奇。
我的对象比这个更复杂,但这应该说明我在尝试什么。
public class Customer
{
public string Name { get; set; }
public List<Contact> Contacts { get; set; }
}
public class Contact
{
public string Name { get; set; }
public List<Email> EmailAddresses {get; set;}
}
public class Email
{
public string EmailAddress {get; set;}
}
private void TrimWhitespace(object instance)
{
if (instance != null)
{
var props = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
// Ignore indexers
.Where(prop => prop.GetIndexParameters().Length == 0)
// Must be both readable and writable
.Where(prop => prop.CanWrite && prop.CanRead);
foreach (PropertyInfo prop in props)
{
if (instance is IEnumerable)
{
foreach (var item in (IEnumerable)instance)
{
TrimWhitespace(item);
}
}
else if (prop.GetValue(instance, null) is string)
{
string value = (string)prop.GetValue(instance, null);
if (value != null)
{
value = value.Trim();
prop.SetValue(instance, value, null);
}
}
else
TrimWhitespace(prop.GetValue(instance, null));
}
}
}
有何想法?
Expression
也会很麻烦;将多个Action<T,string>
组合成单个委托会很好地解决问题。 - Marc GravellCompile
)的树不具备这种能力。 - Marc Gravell