繁体   English   中英

将潜在错误的定界字符串解析为类的最有效方法是什么?

[英]What's the most efficient way to parse a potentially bad delimited string into a class?

我正在构建一个自定义解析器,该解析器应读取定界数据列表,并将结果存储在类中。 我的问题是,生成数据的程序并不总是包含所有定界符。

例如,如果后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循环,但是我不确定这样做对性能有何影响,我想先看看是否有更好的方法。

假设属性为空

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];

扩展方法怎么样?

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

假设您的属性命名方案实际上类似于您的示例,则可以通过反射来实现:

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设置它们。

创建属性数组将起作用,即。 Xander的答案,但是仍然不能解决不良数据的问题。 如果文件中间的字段分隔错误,则数组中间的属性也会出现问题。

但是,当您遇到问题时,我认为失败没有任何错。 如果消息格式错误,则该数据将是错误的。 如果您不需要创建缺少的字段,则总是可以手动解析消息并修复分隔错误的部分。

如果需要缺少字段,则某些应用程序会使用算法尝试修复错误的数据。 如果您认为数据可以固定(通过创建新数据或按摩旧数据),则可以创建一种“猜测”缺失字段的算法。

我会考虑对您的属性名称创建一个查找表,将属性的预期索引映射到其属性名称。 然后通过反射设置属性。

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

提供另一种方式...

如果具有默认值(例如空字符串),则可以创建一个List并使用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]; 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM