Словарь обобщенного делегата Parser <T> - PullRequest
0 голосов
/ 02 ноября 2011

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

Мой первый удар, заимствование идей из Словарь с делегатами разных типов: более чистые, не строковые имена методов?

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

Я застрял при повторном обнаружении типа синтаксического анализатора, когда мне нужно его использовать. Мне нужно привести его обратно к Parser<double>, Parser<int> и т. Д. В зависимости от PropertyInfo.

Консервативный анализатор CSV в этом случае не работает, так как свойства домена получены из нескольких файлов.

Ответы [ 3 ]

0 голосов
/ 02 ноября 2011

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

Могут ли они все использовать интерфейс? в этом случае у вас может быть метод abstract MyInterface CreateOne(), который сообщает об экземпляре, который вы можете реализовать в каждом классе. В противном случае подход из вопроса, вероятно, будет работать лучше всего.

С уважением GJ

0 голосов
/ 02 ноября 2011

Хотя у меня может не быть полной картины, похоже, вы делаете вещи более сложными, чем они должны быть.

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

Тем не менее, для обеспечения работоспособности вашего текущего решения, возможно, проще всего использовать динамический вызов делегатов:

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 );
0 голосов
/ 02 ноября 2011

Если создавать собственный парсер не обязательно, используйте Irony .Его в C # и прост в использовании.Зачем изобретать заново?!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...