修剪所有字符串属性
我需要在我的对象中修剪一些字符串属性,但我不想去所有对象和属性,并且在set属性中做Trim方法(有很多对象,300+和很多字符串属性) 。
一个提示:我的所有对象都有一个名为CoreTransaction的超类,所以我可以使用它(带某种reflection)来更容易地做这件事。
那可能吗?
谢谢。
var stringProperties = obj.GetType().GetProperties() .Where(p => p.PropertyType == typeof (string)); foreach (var stringProperty in stringProperties) { string currentValue = (string) stringProperty.GetValue(obj, null); stringProperty.SetValue(obj, currentValue.Trim(), null) ; }
感谢Bala R解决OP的问题。 我将您的解决方案转换为扩展方法并修复了空值抛出错误的问题。
/// Trim all String properties of the given object public static TSelf TrimStringProperties(this TSelf input) { var stringProperties = input.GetType().GetProperties() .Where(p => p.PropertyType == typeof(string)); foreach (var stringProperty in stringProperties) { string currentValue = (string)stringProperty.GetValue(input, null); if (currentValue != null) stringProperty.SetValue(input, currentValue.Trim(), null); } return input; }
我编写了一个扩展方法,它还处理引用类的子类和字符串(如parent.Child.Name)
public static class ExtensionMethods { public static void TrimAllStrings(this TSelf obj) { BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; foreach (PropertyInfo p in obj.GetType().GetProperties(flags)) { Type currentNodeType = p.PropertyType; if (currentNodeType == typeof (String)) { string currentValue = (string)p.GetValue(obj, null); if (currentValue != null) { p.SetValue(obj, currentValue.Trim(), null); } } // see http://stackoverflow.com/questions/4444908/detecting-native-objects-with-reflection else if (currentNodeType != typeof (object) && Type.GetTypeCode(currentNodeType) == TypeCode.Object) { p.GetValue(obj, null).TrimAllStrings(); } } } }
我不确定如何改变访问者的行为。 这听起来并不容易。 如何将修剪添加到基类?
class CoreTransaction { public void Trim() { IEnumerable stringProperties = this.GetType().GetProperties() .Where(p => p.PropertyType == typeof(string) && p.CanRead && p.CanWrite); foreach (PropertyInfo property in stringProperties) { string value = (string)property.GetValue(this, null); value = value.Trim(); property.SetValue(this, value, null); } } }
(另请注意,检查您的字段是否可以读取和写入。)
编辑:然后你可以添加这样的东西到你的基类,并一次修剪所有这些。 WeakReference类将允许您轻松跟踪您的实例,而不会妨碍垃圾收集器:
class CoreTransaction { private static List allCoreTransactions = new List (); public CoreTransaction() { allCoreTransactions.Add(new WeakReference(this)); } public static void TrimAll() { foreach (WeakReference reference in allCoreTransactions) { if (reference.IsAlive) { ((CoreTransaction)reference.Target).Trim(); } } } }
您可以使用reflection来执行以下操作:
// o is your instance object List fields = o.GetType().GetProperties() .Where(i => i.PropertyType == typeof(string)); fields.ForEach(i => i.SetValue(o, ((string)i.GetValue(o, null)).Trim(), new object[]{}));
感谢landi的解决方案。 我改变了他的方法来添加对带有索引参数的类的支持,并在继续之前检查obj是否为null。
public static void TrimAllStrings(this TSelf obj) { if (obj == null) return; BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; foreach (PropertyInfo p in obj.GetType().GetProperties(flags)) { Type currentNodeType = p.PropertyType; if (currentNodeType == typeof(String)) { string currentValue = (string)p.GetValue(obj, null); if (currentValue != null) { p.SetValue(obj, currentValue.Trim(), null); } } // see http://stackoverflow.com/questions/4444908/detecting-native-objects-with-reflection else if (currentNodeType != typeof(object) && Type.GetTypeCode(currentNodeType) == TypeCode.Object) { if (p.GetIndexParameters().Length == 0) { p.GetValue(obj, null).TrimAllStrings(); }else { p.GetValue(obj, new Object[] { 0 }).TrimAllStrings(); } } } }
我修复了landi的答案以容纳子可空对象并处理IEnumerable集合(循环遍历对象列表和修剪字符串属性)。 我对他的答案进行了编辑,因为没有主题而被拒绝了,但那是一堆垃圾。 希望这有助于某人,因为兰迪的回答并不适用于我所拥有的每种对象类型。 现在确实如此。
public static class ExtensionMethods { public static void TrimAllStrings(this TSelf obj) { if(obj != null) { if(obj is IEnumerable) { foreach(var listItem in obj as IEnumerable) { listItem.TrimAllStrings(); } } else { BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; foreach (PropertyInfo p in obj.GetType().GetProperties(flags)) { Type currentNodeType = p.PropertyType; if (currentNodeType == typeof (String)) { string currentValue = (string)p.GetValue(obj, null); if (currentValue != null) { p.SetValue(obj, currentValue.Trim(), null); } } // see http://stackoverflow.com/questions/4444908/detecting-native-objects-with-reflection else if (currentNodeType != typeof (object) && Type.GetTypeCode(currentNodeType) == TypeCode.Object) { p.GetValue(obj, null).TrimAllStrings(); } } } } } }
对于那些使用VB.NET的人,我转换了thrawnis的答案并添加了一个条件,只返回那些不是ReadOnly的属性。 否则,如果您的类具有只读属性,则在尝试为这些属性设置SetValue时将出现运行时错误。
''' ''' Trim all NOT ReadOnly String properties of the given object ''' Public Function TrimStringProperties(Of T)(ByVal input As T) As T Dim stringProperties = input.GetType().GetProperties().Where(Function(p) p.PropertyType = GetType(String) AndAlso p.CanWrite) For Each stringProperty In stringProperties Dim currentValue As String = Convert.ToString(stringProperty.GetValue(input, Nothing)) If currentValue IsNot Nothing Then stringProperty.SetValue(input, currentValue.Trim(), Nothing) End If Next Return input End Function
你可以尝试一下:
static public class Trim where T : class { static public readonly Action TrimAllStringFields = Trim .CreateTrimAllStringFields(); static private Action CreatTrimAllStringFields() { var instance = Expression.Parameter(typeof(T)); return Expression.Lambda>(Expression.Block(instance.Type.GetFields(BindingsFlags.Instance| BindingFlags.NonPublic | BindingFlags.Public).Select(field => Expression.Assign(Expression.Field(instance, field)) as Expression), instance).Compile(); } }
像这样用它:
var myinstance = new MyClass(); Trim.TrimAllStringFields(myinstance);