开发者

Trying to write a pleasant parser

I am writing a simple parser that will take a string of the format 20100101,1,2,foo and create an instance of the following class:

public class Foo
{
    public DateTime TheDate { get; set; }
    public int TheFirstInt { get; set; }
    public int TheSecondInt { get; set; }
    public string TheString { get; set; }
}

I would like to be able to declare my parsers for each property as an开发者_运维百科 array of (for example) Func<>s in an attempt to make the code more readable (from a point of view of correlating items in the string with the parsing code that is used).

// Production code would contain parsers with error checking etc.
Func<string, object>[] parsers = new Func<string, object>[]
{
    s => DateTime.ParseExact(s, "yyyyMMdd", CultureInfo.InvariantCulture),
    s => int.Parse(s),
    s => int.Parse(s),
    s => s
};

I would then like to be able to iterate through the parsers, properties of FooClass and values in fooItems in one loop:

Foo fooInstance = new Foo();
string[] fooItems = fooString.Split(',');

for (int i = 0; i < parsers.Length; i++)
{
    fooInstance.Properties[i] = parsers[i](fooItems[i]);
    // range-checking and error handling excluded from this example
}

However, this of course won't work because:

  • It doesn't address how you might be able to iterate through the properties of fooInstance
  • It doesn't deal with casting of values parsed

Any thoughs on how to write a "pleasant" parser like this?


I'd try to use Actions instead of Funcs and set the properties directly:

Action<string, FooClass>[] actions = new Action<string, FooClass>[] {
    (s, c) => c.TheDate = DateTime.ParseExact(s, "yyyyMMdd", CultureInfo.InvariantCulture),
    (s, c) => c.TheFirstInt = Int32.Parse(s)
    // ...
}

for (int i = 0; i < fooItems.Length; ++i)
    actions[i](fooItems[i], fooInstance);


I know this isn't answering your question directly, but if you find your "language" gets much more complicated then I recommend using Irony to parse it: http://www.codeplex.com/irony

If your language is going to stay in a flat format (like CSV), then it's worth looking at http://www.filehelpers.com/

In your example, you'd just need to annotate your class:

[DelimitedRecord(",")]
public class Foo
{
    [FieldConverter(ConverterKind.Date, "yyyyMMdd")]
    public DateTime TheDate { get; set; }
    public int TheFirstInt { get; set; }
    public int TheSecondInt { get; set; }
    public string TheString { get; set; }
}

then parse it with:

FileHelperEngine engine = new FileHelperEngine(typeof(Foo));
Foo[] fs = engine.ReadFile("FileIn.txt") as Foo[];


You need to use reflection : eg :

fooInstance.GetType().GetProperty("SomeProp").SetValue(fooInstance, "SomeProp", val);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜