【问题标题】:Dictionary of generic delegate Parser<T>泛型委托 Parser<T> 字典
【发布时间】:2012-03-14 08:12:54
【问题描述】:

我想创建一个解析器,将字符串标记转换为基于键的类型化对象。

我的第一次尝试,借鉴Dictionary<T,Delegate> with Delegates of different types: Cleaner, non string method names?的想法

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

当我需要使用解析器时,我陷入了重新发现解析器类型的困境。我需要根据PropertyInfo 将其转换回Parser&lt;double&gt;Parser&lt;int&gt; 等。

标准 CSV 解析器在这种情况下不起作用,因为域的属性来自多个文件。

【问题讨论】:

    标签: c# generics delegates


    【解决方案1】:

    虽然我可能没有完整的了解,但看起来你让事情变得比他们需要的更复杂。

    PropertyType 上的简单开关和适当解析方法的直接调用将使代码更易于理解和维护。如果您担心反射成本,请使用 a library 生成直接引用该属性的委托。

    也就是说,要使您当前的解决方案发挥作用,最简单的方法可能是使用委托的动态调用:

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

    我也忍不住提到上面引用的库提供的扩展方法,它允许您从一组值创建对象实例(数据类型不需要匹配,类型会根据需要自动转换/强制转换),像这样:

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

    【讨论】:

      【解决方案2】:

      如果不是绝对需要创建自己的解析器,请使用Irony。它在 C# 中并且易于使用。为什么要重新发明?!

      【讨论】:

      • 这很好,但对我们的团队来说太过分了。我们只需要将标记转换为对象。
      • 好的!但请记住,您编写的代码越多,您创建的错误就越多! :) 另外,在 Irony 中实现语法将花费不到 30 分钟的时间来完成整个语言。
      【解决方案3】:

      如果您想根据某个键来新建对象,请查看this 问题,看起来非常相似。在您的情况下,听起来您甚至不必使用反射,因为您要创建的对象类型是已知的。

      他们都可以共享一个接口吗?在这种情况下,您可以拥有一个 abstract MyInterface CreateOne() 方法,该方法会通知您可以在每个类上实现的实例。否则问题中的方法可能效果最好。

      问候 GJ

      【讨论】:

      • 我需要使用 double.Parse 将字符串转换为双精度。
      • 那么......究竟是什么让你不这样做?我没有从问题中得到这一点。您是否有一些您正在解析的文件的示例以及您卡在哪里?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      相关资源
      最近更新 更多