Обрезать все свойства строки - PullRequest
14 голосов
/ 11 октября 2011

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

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

возможно?

Спасибо.

Ответы [ 9 ]

35 голосов
/ 11 октября 2011
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) ;
}
15 голосов
/ 11 марта 2013

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

    /// <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;
    }
6 голосов
/ 27 августа 2015

Я написал метод расширения, который также заботится о подклассах и строках в ссылочных классах (например, 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 /3091988/obnaruzhenie-nativnyh-obektov-s-otrazheniem
            else if (currentNodeType != typeof (object) && Type.GetTypeCode(currentNodeType) == TypeCode.Object)
            {
                p.GetValue(obj, null).TrimAllStrings();
            }
        }
    }
}
4 голосов
/ 11 октября 2011

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

    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();
            }
        }
    }
}
2 голосов
/ 05 мая 2018

Я исправил ответ Ланди, чтобы приспособить дочерние обнуляемые объекты и обрабатывать коллекции IEnumerable (просмотр списка свойств объекта и строки обрезки). Я отредактировал его ответ, который был отклонен за то, что он не был по теме, но это куча мусора. Надеюсь, это кому-нибудь поможет, поскольку ответ Ланди не сработал для всех типов объектов, которые у меня были. Теперь это так.

public static class ExtensionMethods
{
    public static void TrimAllStrings<TSelf>(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 /3091988/obnaruzhenie-nativnyh-obektov-s-otrazheniem
                    else if (currentNodeType != typeof (object) && Type.GetTypeCode(currentNodeType) == TypeCode.Object)
                    {
                        p.GetValue(obj, null).TrimAllStrings();
                    }
                }
            }
        }
    }
}
2 голосов
/ 11 октября 2011

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

// 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[]{}));
1 голос
/ 09 февраля 2017

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

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 /3091988/obnaruzhenie-nativnyh-obektov-s-otrazheniem
            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();
                }
            }
        }
    }
0 голосов
/ 15 июля 2015

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

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);
0 голосов
/ 14 июля 2015

Для тех, кто использует VB.NET, я преобразовал ответ thrawnis и добавил условие, чтобы возвращать только те свойства, которые не являются 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...