我想创建一个解析器,它根据键将字符串标记转换为类型化对象。
我的第一次尝试,借鉴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;
}
}
当我需要使用它时,我无法重新发现解析器的类型。我需要根据Parser<double>
将其强制转换回Parser<int>
,PropertyInfo
等。
在这种情况下,固定的CSV解析器不起作用,因为Domain的属性来自多个文件。
答案 0 :(得分:0)
如果创建自己的解析器不是绝对必要的,请使用Irony。它在C#中易于使用。为什么要重新发明?!
答案 1 :(得分:0)
如果你想根据某个键新建对象,请查看this问题,看起来非常相似。在你的情况下,你甚至不必使用反射,因为你想要创建的对象类型已经知道。
他们都可以共享界面吗?在这种情况下,您可以使用abstract MyInterface CreateOne()
方法来通知您可以在每个类上实现的实例。否则问题的方法可能效果最好。
关心GJ
答案 2 :(得分:0)
虽然我可能没有完整的图片,但看起来你做的事情比他们需要的更复杂。
对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 );