Есть ли способ создать список передаваемых ссылок на переменные управляемого типа? - PullRequest
0 голосов
/ 13 апреля 2020

редактировать; Основываясь на ответах, я, возможно, был неясен в своей конечной цели. Я обновил последний раздел.

Ситуация

У меня есть ряд переменных, с которыми мне нужно выполнить ту же операцию. В этом случае они равны strings и могут в момент, когда мы достигнем этого кода, иметь значение null, "", "Blank", или они могут уже иметь другое назначенное значение, которое я хочу сохранить.

if (String.IsNullOrEmpty(MyVar1) || "Blank".Equals(MyVar1))
    MyVar1 = null;
if(String.IsNullOrEmpty(MyVar2) || "Blank".Equals(MyVar2))
    MyVar2 = null;
...
if(String.IsNullOrEmpty(MyVar10) || "Blank".Equals(MyVar10))
    MyVar10 = null;

Будучи программистом, который хочет сохранить мой код в чистоте, и этот блок сводит меня с ума, я ищу способ создать список этих переменных и выполнить то же самое выражение if + null назначение на каждого.

Например, вот что я хотел бы сделать:

MyVar1 = "Blank";
DreamDataStructure varList = new DreamDataStructure() { MyVar1, MyVar2, ..., MyVar10 };
foreach(ref string MyVar in varList)
{
    if(String.IsNullOrEmpty(MyVar) || "Blank".Equals(MyVar))
        MyVar = null;
}
Console.WriteLine(MyVar1); //Should now be null

Что не работает

1) Потому что мои переменные strings, я не могу сделать что-то подобное.

var myListOfVariables = new[] { &MyVar1, &MyVar2, ..., &MyVar10 };

Если бы я мог, я мог бы foreach над ними, как и ожидалось. Поскольку string является управляемым типом, он не может передаваться по ссылке следующим образом.

2) Точно так же, если бы я просто сделал List<string> переменных, они были бы переданы по значению и не могли бы В моем случае это не поможет.

3) Эти переменные не могут быть обернуты во внешний тип объекта, так как их необходимо использовать в качестве строк в большом количестве мест в унаследованном приложении. Предположим, что было бы слишком сложно изменить их в каждом месте.

Вопрос

Есть ли способ перебрать string ( или другие переменные управляемого типа) путем передачи по ссылке, что позволит мне поместить всю операцию внутри al oop и уменьшить дублирование кода, который здесь происходит?

Цель в том, чтобы Я могу использовать исходные переменные позже в моем коде с обновленными значениями. На MyVar1 и т. Д. c позже ссылается уже унаследованный код, который ожидает, что они будут null или имеют фактическое значение.

Ответы [ 4 ]

1 голос
/ 13 апреля 2020

Если я правильно понимаю ваш вопрос, я не думаю, что вы хотите сделать возможно. Пожалуйста, посмотрите этот вопрос: Интересная функция "params of ref", какие-нибудь обходные пути?

Единственное, что я могу предложить (что я знаю, не отвечает на ваш вопрос) - это создать метод для избегайте дублирования ваших условных логи c:

void Convert(ref string text)
{
    if (string.IsNullOrEmpty(text) || "Blank".Equals(text))
    {
        text = null;
    }
}
0 голосов
/ 13 апреля 2020

Вы можете создать функцию вместо передачи ссылок, что также будет более читабельным.

string Validate(string inputString)
{
   return string.IsNullOrEmpty(inputString) || "Blank".Equals(inputString) ? null : inputString;
}

<...>
 MyVar1 = Validate(MyVar1);
0 голосов
/ 13 апреля 2020

Обновление:

Теперь я понимаю, что вы пытаетесь сделать. У вас есть куча переменных, и вы хотите выполнить какую-то массовую операцию над ними, ничего не меняя. Поместить их в класс не вариант.

В этом случае вы действительно застряли, работая с ними по одному. Есть способы сократить его, но вы в значительной степени застряли с повторением.

Я бы

  • создал бы string SanitizeString(string input) функцию
  • type x = SanitizeString(x); один раз для каждой переменной
  • скопируйте и вставьте имена переменных, чтобы заменить x.

Это плохо, но это почти все, что есть.


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

public class MyValues
{
    private string _value1;
    private string _value2;
    private string _value3;

    public string Value1
    {
        get { return _value1; }
        set { _value1 = Sanitize(value); }
    }

    // repeat for other values

    private string Sanitize(string input) =>
        string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
}

Это один из вариантов. Другой - дезинфицировать входные данные ранее. Но в идеале мы хотим убедиться, что данный класс всегда находится в допустимом состоянии. Мы бы не хотели иметь экземпляр класса, независимо от того, допустимы ли значения или нет. Лучше убедиться, что они всегда действительны.

ref на самом деле не учитывает это. Нам не нужно использовать его часто, если вообще. С типом значения или string мы можем просто вернуть новое значение из функции.

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

Сначала я попытаюсь написать методы, не используя ref, и использую их только в случае необходимости. Вы, вероятно, никогда не будете, потому что вы преуспеете в том, что вы пытаетесь сделать без использования ref.


В вашем комментарии упоминалось, что это устаревшее приложение, и желательно не изменять существующий класс , Это оставляет еще один вариант - отражение. Не мой любимый, но когда вы говорите «устаревшее приложение», я чувствую вашу боль. В этом случае вы можете сделать это:

public static class StringSanitizer
{
    private static Dictionary<Type, IEnumerable<PropertyInfo>> _stringProperties = new Dictionary<Type, IEnumerable<PropertyInfo>>();

    public static void SanitizeStringProperties<T>(T input) where T : class
    {
        if (!_stringProperties.ContainsKey(typeof(T)))
        {
            _stringProperties.Add(typeof(T), GetStringProperties(typeof(T)));
        }

        foreach (var property in _stringProperties[typeof(T)])
        {
            property.SetValue(input, Sanitize((string)property.GetValue(input)));
        }
    }

    private static string Sanitize(string input)
    {
        return string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
    }

    private static IEnumerable<PropertyInfo> GetStringProperties(Type type)
    {
        return type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(property => property.PropertyType == typeof(string) && property.CanRead && property.CanWrite);
    }
}

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

StringSanitizer.SanitizeStringProperties(someObject);
0 голосов
/ 13 апреля 2020

Вы можете просто использовать строку [] и вернуть изменения в метод вызывающего абонента следующим образом.

public Main()
{
    var myVar1 = "Blank";
    var myVar2 = "";
    string myVar3 = null;
    var myVar4 = "";
    string[] dreamDataStructure = new string[] { myVar1, myVar2, myVar3, myVar4 };
}

private void ProcessStrings(string[] list)
{
    for(int i = 0; i < list.Length; i++)
    {

        if (String.IsNullOrEmpty(list[i]) || "Blank".Equals(list[i]))
            list[i] = null;
    }
}
...