简体   繁体   English

通用委托解析器字典<T>

[英]Dictionary of generic delegate Parser<T>

I want to create a parser that convert string tokens to typed objects based on a key. 我想创建一个解析器,将基于键的字符串标记转换为键入的对象。

My first stab, borrowing ideas from Dictionary<T,Delegate> with Delegates of different types: Cleaner, non string method names? 我的第一个选项是从Dictionary <T,Delegate>借用具有不同类型的委托的想法:干净的非字符串方法名称?

delegate T Parser<T>(string item);

public class TableParser    
{
    static IDictionary<string, Pair<PropertyInfo, Delegate>> _PARSERS;
    static Type DOMAIN_TYPE;

    static TableParser()
    {
        DOMAIN_TYPE= typeof(Domain);

        Dictionary<string, Pair<PropertyInfo, Delegate>> parsers = new
            Dictionary<string, Pair<PropertyInfo, Delegate>>()
        {
            { "PropertyOne", new Pair<PropertyInfo,Delegate>(
                DOMAIN_TYPE.GetProperty("PropertyOne"), 
                (Parser<double>) double.Parse ) },
        };
        _PARSERS = parsers;
    }

    public List<Domain> Parse(string filename)
    {
        List<Domain> domains = new List<Domain>();

        List<List<string>> data = 
            CVSParser.Instance.Parse(filename);
        List<string> headers = data[0];

        for (int i = 1; i < data.Count; i++)
        {
            List<string> row = data[i];
        }            

        return domains;
    }

    private Dictionary<int, Pair<PropertyInfo, Delegate>> FindParsers(List<string> headers)
    {
        Dictionary<int, Pair<PropertyInfo, Delegate>> parsers =
            new Dictionary<int, Pair<PropertyInfo, Delegate>>();

        int i = 0;
        headers.ForEach(h =>
        {
            if (_PARSERS.ContainsKey(h))
            {
                parsers[i] = _PARSERS[h];
            }
            ++i;
        });

        return parsers;
    }

    private Domain Create(List<string> data,
        Dictionary<int, Pair<PropertyInfo, Delegate>> parsers)
    {
        Domain domain = new Domain();

        foreach (KeyValuePair<int, Pair<PropertyInfo, Delegate>> parser in parsers)
        {
            string datum = data[parser.Key];
            parser.Value.First.SetValue(domain,
                /* got stuck here */ parser.Value.Second,
                null);

        }

        return domain;
    }
}

I got stuck at re-discovering the type of the parser when I need to use it. 当我需要使用解析器时,我被困在重新发现它的类型上。 I need to cast it back to Parser<double> , Parser<int> , etc depending on PropertyInfo . 我需要根据PropertyInfo将其Parser<double>Parser<double>Parser<int>等。

A canned CSV parser doesn't work in this case because Domain's properties come from multiple files. 罐装CSV分析器在这种情况下不起作用,因为Domain的属性来自多个文件。

If its not absolutely necessary to create your own parser, use Irony . 如果创建您自己的解析器不是绝对必要的,请使用Irony Its in C# and easy to use. 它在C#中易于使用。 Why re-invent?! 为什么要重新发明?

If you want to new up object based on some key, please have a look at this question, it seems quite similar. 如果您想基于某个键来更新对象,请看一下这个问题,看起来很相似。 In your case it sounds like you wouldn't even have to use reflection because the types of objects you want to create are already known. 在您的情况下,您听起来甚至不必使用反射,因为您要创建的对象的类型已经知道。

Can they all share an Interface? 他们都可以共享一个接口吗? in that case you can have an abstract MyInterface CreateOne() method that news up an instance that you can implement on each class. 在那种情况下,您可以有一个abstract MyInterface CreateOne()方法,该方法abstract MyInterface CreateOne()可以在每个类上实现的实例。 Else the approach from the question would probably work best. 否则,该问题的方法可能会最好。

Regards GJ 关于GJ

Although I may not have the full picture, it looks like you're making things more complicated than they need to be. 尽管我可能没有完整的画面,但看起来您正在使事情变得比其所需要的更为复杂。

A simple switch on the PropertyType and direct invocations of the appropriate parse methods would make the code simpler to understand and maintain. 对PropertyType的简单切换以及对适当解析方法的直接调用将使代码更易于理解和维护。 If the cost of reflection worries you, use a library to generate delegates that refer directly to the property. 如果您担心反射的开销,请使用来生成直接引用该属性的委托。

That said, to make your current solution work, the easiest is probably to use dynamic invocation of the delegates: 就是说,要使当前的解决方案正常工作,最简单的方法可能是使用委托的动态调用:

parser.Value.First.SetValue(analytic, 
    parser.Value.Second.DynamicInvoke(datum),
    null);

I also cannot resist mentioning the extension methods provided by the library referenced above, which allows you to create object instances from a set of values (the data types do not need to match, types are automatically converted/coerced as needed), like this: 我也不能不提及上面提到的库提供的扩展方法,该方法允许您从一组值创建对象实例(数据类型不需要匹配,类型将根据需要自动转换/强制),如下所示:

var properties = new [] { "One", "Two" };
var inputValues = new object[] { 1.0d, "foobar" };
var domain = typeof(Domain).TryCreateInstance( properties, inputValues );

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

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