Подтвердить что ты не робот

Обрезать все свойства строки

Мне нужно обрезать некоторые свойства строки в моих объектах, но я не хочу обращаться ко всем объектам и свойствам, а в заданном правиле использовать метод Trim (существует много объектов, 300+ и много строковые свойства).

Один совет: все мои объекты имеют суперкласс под названием CoreTransaction, поэтому я могу использовать его (с каким-то отражением), чтобы сделать это проще.

Возможно ли это?

Спасибо.

4b9b3361

Ответ 1

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) ;
}

Ответ 2

Спасибо Bala R за ваше решение проблемы OP. Я преобразовал ваше решение в метод расширения и исправил проблему, когда нулевые значения выбрасывали ошибки.

    /// <summary>Trim all String properties of the given object</summary>
    public static TSelf TrimStringProperties<TSelf>(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;
    }

Ответ 3

Я не уверен в изменении поведения ваших аксессуаров. Это совсем не так просто. Как добавить обрезку в базовый класс?

    class CoreTransaction
    {
        public void Trim()
        {
            IEnumerable<PropertyInfo> 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<WeakReference> allCoreTransactions = new List<WeakReference>();

    public CoreTransaction()
    {
        allCoreTransactions.Add(new WeakReference(this));
    }

    public static void TrimAll()
    {
        foreach (WeakReference reference in allCoreTransactions)
        {
            if (reference.IsAlive)
            {
                ((CoreTransaction)reference.Target).Trim();
            }
        }
    }
}

Ответ 4

Я написал метод расширения, который также заботится о подклассах и строках на ссылочных классах (например, parent.Child.Name)

public static class ExtensionMethods
{
    public static void TrimAllStrings<TSelf>(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();
            }
        }
    }
}

Ответ 5

Вы можете использовать отражение, чтобы сделать что-то вроде этого:

// o is your instance object 
List<PropertyInfo> fields = o.GetType().GetProperties()
        .Where(i => i.PropertyType == typeof(string));
fields.ForEach(i => i.SetValue(o, ((string)i.GetValue(o, null)).Trim(), new object[]{}));

Ответ 6

Спасибо landi за его решение. Я изменил его метод, чтобы добавить поддержку классов с индексными параметрами, а также проверить, является ли obj нулевым до продолжения.

public static void TrimAllStrings<TSelf>(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();
                }
            }
        }
    }

Ответ 7

Для тех, кто использует VB.NET, я конвертировал thrawnis-ответ и добавил условие, чтобы возвращать только те свойства, которые не являются ReadOnly. В противном случае, если ваш класс имеет свойства readonly, вы получите ошибку времени выполнения при попытке SetValue для этих свойств.

''' <summary>
''' Trim all NOT ReadOnly String properties of the given object
''' </summary>
<Extension()>
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

Ответ 8

Вы можете попробовать:

static public class Trim<T>
    where T : class
{
    static public readonly Action<T> TrimAllStringFields = Trim<T>.CreateTrimAllStringFields();

    static private Action<T> CreatTrimAllStringFields()
    {
        var instance = Expression.Parameter(typeof(T));
        return Expression.Lambda<Action<T>>(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<MyClass>.TrimAllStringFields(myinstance);