С#: как получить все публичные (как get и set) строковые свойства типа - программирование
Подтвердить что ты не робот

С#: как получить все публичные (как get и set) строковые свойства типа

Я пытаюсь сделать метод, который будет проходить через список общих объектов и заменить все их свойства типа string, который либо является null, либо пустым с заменой.

Как хороший способ сделать это?

У меня есть такая... оболочка... пока:

public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
    var properties = typeof(T).GetProperties( -- What BindingFlags? -- );

    foreach(var p in properties)
    {
        foreach(var item in list)
        {
            if(string.IsNullOrEmpty((string) p.GetValue(item, null)))
                p.SetValue(item, replacement, null);
        }
    }
}

Итак, как мне найти все свойства типа:

  • Тип string
  • Публичный get
  • Публичный set

    ?


Я сделал этот тестовый класс:

class TestSubject
{
    public string Public;
    private string Private;

    public string PublicPublic { get; set; }
    public string PublicPrivate { get; private set; }
    public string PrivatePublic { private get; set; }
    private string PrivatePrivate { get; set; }
}

Не работает следующее:

var properties = typeof(TestSubject)
        .GetProperties(BindingFlags.Instance|BindingFlags.Public)
        .Where(ø => ø.CanRead && ø.CanWrite)
        .Where(ø => ø.PropertyType == typeof(string));

Если я распечатаю имя тех свойств, которые у меня есть, я получаю:

PublicPublic государственно-частное PrivatePublic

Другими словами, я получаю два свойства слишком много.


Примечание. Это, вероятно, можно было бы сделать лучше... используя вложенный foreach и отражение и все здесь... но если у вас есть какие-то отличные альтернативные идеи, пожалуйста, дайте мне знать, потому что я хочу учиться!

4b9b3361

Ответ 1

Ваш код переписан. Не использует LINQ или var.

public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
    PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

    foreach (PropertyInfo p in properties)
    {
        // Only work with strings
        if (p.PropertyType != typeof(string)) { continue; }

        // If not writable then cannot null it; if not readable then cannot check it value
        if (!p.CanWrite || !p.CanRead) { continue; }

        MethodInfo mget = p.GetGetMethod(false);
        MethodInfo mset = p.GetSetMethod(false);

        // Get and set methods have to be public
        if (mget == null) { continue; }
        if (mset == null) { continue; }

        foreach (T item in list)
        {
            if (string.IsNullOrEmpty((string)p.GetValue(item, null)))
            {
                p.SetValue(item, replacement, null);
            }
        }
    }
}

Ответ 2

Вы найдете свойства как таковые с BindingFlags.Public | BindingFlags.Instance. Затем вам нужно будет изучить каждый экземпляр PropertyInfo, проверив свойства CanWrite и CanRead, чтобы узнать, являются ли они доступными для чтения и/или записи.

Обновление: пример кода

PropertyInfo[] props = yourClassInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < props.Length; i++)
{
    if (props[i].PropertyType == typeof(string) && props[i].CanWrite)
    {
        // do your update
    }
}

Я просмотрел его более подробно после вашего обновления. Если вы также изучите объекты MethodInfo, возвращаемые GetGetMethod и GetSetMethod, вы попадете в цель, я думаю:

 var properties = typeof(TestSubject).GetProperties(BindingFlags.Instance | BindingFlags.Public)
        .Where(ø => ø.CanRead && ø.CanWrite)
        .Where(ø => ø.PropertyType == typeof(string))
        .Where(ø => ø.GetGetMethod(true).IsPublic)
        .Where(ø => ø.GetSetMethod(true).IsPublic);

По умолчанию эти два метода возвращают только публичные геттеры и сеттеры (рискуя исключением NullReferenceException в таком случае), но передача true, как указано выше, делает их также возвратными частными. Затем вы можете изучить свойства IsPublic (или IsPrivate).

Ответ 3

Если вы не укажете какие-либо флаги привязки, вы получите общедоступные свойства экземпляра - это то, что вы хотите. Но тогда вам нужно будет проверить, имеет ли свойство PropertyType объект PropertyInfo тип String. Если вы не знаете заранее, вам также нужно будет проверить, является ли свойство доступным для чтения/записи, как указывает @Fredrik.

using System.Linq;

public static void ReplaceEmptyStrings<T>(List<T> list, string replacement)
{
    var properties = typeof(T).GetProperties()
                              .Where( p => p.PropertyType == typeof(string) );
    foreach(var p in properties)
    {
        foreach(var item in list)
        {
            if(string.IsNullOrEmpty((string) p.GetValue(item, null)))
                p.SetValue(item, replacement, null);
        }
    }
}

Ответ 5

BindingFlags.Public | BindingFlags.Instance должен это сделать

GetSetMethod()

Ответ 6

Я предлагаю другой подход: AOP.
Вы можете перехватить сеттер и установить желаемое значение в действительное. С PostSharp это довольно просто.

Ответ 7

Я согласен с другими ответами, но я предпочитаю реорганизовать сам поиск, который будет легко запрошен Linq, поэтому запрос может быть следующим:

        var asm = Assembly.GetExecutingAssembly();
        var properties = (from prop
                              in asm.GetType()
                                .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                          where 
                            prop.PropertyType == typeof (string) && 
                            prop.CanWrite && 
                            prop.CanRead
                          select prop).ToList();
        properties.ForEach(p => Debug.WriteLine(p.Name));

Я взял для своего примера тип Assembly, который не имеет свойств чтения/записи строки, но если тот же поиск кода для только что прочитанных свойств, результатом будет:

  • CodeBase
  • EscapedCodeBase
  • ПолноеИмя
  • Местоположение
  • ImageRuntimeVersion

Каковы строка только для чтения Свойства типа сборки