Какой самый эффективный способ разбить потенциально плохую строку с разделителями в класс? - PullRequest
0 голосов
/ 24 февраля 2012

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

Например, если последние 3 свойства не имеют значения, будут пропущены последние 3 разделителя.

Я использовал что-то подобное, пока не заметил эту причуду:

var data = message.Split(delimiter);

if (data.Length < 5)
    throw new Exception("Invalid message");

Id = data[0];
Property1 = data[1];
Property2 = data[2];
Property3 = data[3];
Property4 = data[4];

Конечно, если строка с разделителями содержит менее 5 элементов, это создает проблему.

Каков наилучший способ разбить потенциально плохую строку с разделителями в класс?

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

Я думал о создании массива всех свойств и запуске цикла for-each в массиве данных, но я не уверен, что это повлияет на производительность, и хотел бы посмотреть, есть ли лучший способ сначала.

Ответы [ 7 ]

3 голосов
/ 24 февраля 2012

Предполагая, что свойства обнуляются

Property1 = data.Length > 1 ? data[1] : null;
Property2 = data.Length > 2 ? data[2] : null;
Property3 = data.Length > 3 ? data[3] : null;
Property4 = data.Length > 4 ? data[4] : null;

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


РЕДАКТИРОВАТЬ:

var dataEx = new string[expectedLength];
data.CopyTo(dataEx, 0);

Property1 = dataEx[1];
Property2 = dataEx[2];
Property3 = dataEx[3];
Property4 = dataEx[4];
2 голосов
/ 24 февраля 2012

Как насчет метода расширения?

public static T GetByIndexOrDefault<T>(this Array array, int index)
{
    if (array == null)
    {
        return default(T);
    }

    if (index <= array.Length)
    {
        return (T)array.GetValue(index - 1);
    }

    return default(T);
}

Тогда:

string data = "foo1;foo2;foo3;foo4";

string[] splittedData = data.Split(';');

string e1 = splittedData.GetByIndexOrDefault<string>(1);    // foo1
string e2 = splittedData.GetByIndexOrDefault<string>(2);    // foo2
string e3 = splittedData.GetByIndexOrDefault<string>(3);    // foo3
string e4 = splittedData.GetByIndexOrDefault<string>(4);    // foo4
string e5 = splittedData.GetByIndexOrDefault<string>(5);    // null
1 голос
/ 24 февраля 2012

Создание массива свойств будет работать, т.е.Ответ Ксандера, однако, это все еще не решение проблемы плохих данных.Если у вас в середине файла есть поле с плохой границей, свойство в середине вашего массива также будет неисправным.

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

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

1 голос
/ 24 февраля 2012

Предполагая, что ваша схема именования недвижимости действительно похожа на ваш пример, вы можете сделать это с помощью отражения:

var data = message.Split(delimiter);
if (data.Length < 1) throw new Exception("Invalid message");
Id = data[0];
for (var i = 1; i < data.Length; i++)
{
    var property = GetType().GetProperty("Property" + i);
    property.SetValue(this, data[i], null);
}

Просто убедитесь, что все ваши свойства имеют приемлемое состояние по умолчанию, если они не установлены message.

0 голосов
/ 24 февраля 2012

Чтобы предоставить еще один способ ...

Если у вас есть значение по умолчанию, например, пустая строка, вы можете создать список и использовать AddRange для добавления значений из строки данных. Затем, если максимальное количество полей для этих конкретных данных не использовалось, используйте AddRange и Enumerable.Repeat, чтобы заполнить оставшиеся значения значением по умолчанию.

        List<string> Results = new List<string>();
        int MaxFields = 5;
        Results.AddRange(message.Split(delimiter));
        if(Results.Count < MaxFields)
            Results.AddRange(Enumerable.Repeat(String.Empty,MaxFields - Results.Count)); 
        Id = Results[0]; 
        Property1 = Results[1];  
        Property2 = Results[2]; 
        Property3 = Results[3]; 
        Property4 = Results[4]; 
0 голосов
/ 24 февраля 2012
using System;
using System.Windows.Forms;
using System.Reflection;
namespace DynamicProp
{
    public partial class Form1 : Form
    {
        class Messagage 
        {
            public string ID { get; set; }
            public string Property1 { get; set; }
            public string Property2 { get; set; }
            public string Property3 { get; set; }
            public string Property4 { get; set; }
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string[] data = { "hasan", "osman", "ali", "veli", "deli" };

            Messagage message = new Messagage();
            PropertyInfo[] ozellikler = message.GetType().GetProperties();
            int I=0;
            foreach (PropertyInfo ozellik in ozellikler)
            {
                ozellik.SetValue(message, data[I], null);
                listBox1.Items.Add("özellik :" + ozellik.Name + "  tipi :"+ozellik.GetValue(message,null).ToString());
                I++;
            }
        }
    }
}
0 голосов
/ 24 февраля 2012

Я хотел бы рассмотреть вопрос о создании таблицы поиска имен ваших свойств, сопоставляя ожидаемый индекс свойства с именем его свойства. Затем установите свойства по отражению.

        string[] propertyLookup = { "Property1", "Property2", "Property3", "Property4", "Property5" };  \\ etc etc
        string[] parsedValues = message.Split(delimiter);
        Foo newFoo = new Foo();
        Type fooType = newFoo.GetType();
        for (int i = 0; i < parsedValues.Count(); i++)
        {
            PropertyInfo prop = fooType.GetProperty(propertyLookup[i]);
            prop.SetValue(newFoo, parsedValues[i], null);
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...