鉴于此界面:
public interface IToken
{
int ID { get; }
string Name { get; }
string Description { get; }
string Type { get; }
string Category { get; }
}
假设我有一个约{200}成员的IEnumerable<IToken>
,它是通过从各种文件中读取JSON构建的。为了测试它,我创建了一个ConsoleApplication项目,我试图通过LINQ操作集合并取得了不错的成功。
我想要做的是从控制台接收输入并通过我设计的命令处理它:
exit
list token
list token filter [filterType] [filterValue]
因此,如果我只输入list token
,它将迭代列表并输出所有成员。容易。
如果我输入list token filter Category "SomeCategory"
(应该选择集合IToken
)中的所有Category == "SomeCategory"
个对象,就会出现问题;我不知道如何编程将用户提供的[filterType]
字符串映射到名为Category
的对象属性(或IToken上可能存在或不存在的其他属性),除非我为每个案例硬编码。对我来说,这太费劲,而且不能很好地扩展。
这样做的最佳方法是什么?
现在,我的代码是:
private void Input_ListTokens(string filterType, string filterValue)
{
IEnumerable<string> result = null;
if (String.IsNullOrWhiteSpace(filterType) || String.IsNullOrWhiteSpace(filterValue))
{
result = from t in Tokens
select t.ToString();
}
else
{
if (filterType == "type")
result = from t in Tokens
where t.Type == filterValue
select t.ToString();
if (filterType == "category")
result = from t in Tokens
where t.Category == filterValue
select t.ToString();
}
if (result != null)
foreach (var item in result)
c.WriteLine(item);
c.WriteLine();
}
正如您在两个LINQ查询之间看到的那样,唯一有形的区别是
where t.Type == filterValue
where t.Category == filterValue
答案 0 :(得分:0)
您可以使用反射或动态LINQ。反思方法:
private void Input_ListTokens(string filterType, string filterValue)
{
var type = typeof(IToken);
var comparison = StringComparison.InvariantCultureIgnoreCase;
var property = type.GetProperties().FirstOrDefault(p =>
p.PropertyType == typeof(string) && p.Name.Equals(filterType, comparison));
if (property == null)
return;
var result = Tokens.Where(t =>
filterValue.Equals((string)property.GetValue(t), comparison));
foreach (var item in result)
Console.WriteLine(item);
}
它搜索IToken
类型中与过滤器类型匹配的字符串属性(不区分大小写)。如果找到匹配项,则将此属性的值与给定的过滤器值进行比较。
对于动态LINQ方法,您应该安装System.Linq.Dynamic包。另请注意,搜索将区分大小写
private void Input_ListTokens(string filterType, string filterValue)
{
var filter = String.Format("{0} = \"{1}\"", filterType, filterValue);
var result = Tokens.AsQueryable().Where(filter);
foreach (var item in result)
Console.WriteLine(item);
}
您还可以构建表达式并将其编译为lambda(您可以使用不区分大小写的属性搜索):
private Func<IToken, bool> CreateFilter(string filterType, string filterValue)
{
var t = Expression.Parameter(typeof(IToken), "token");
var left = Expression.Property(t, typeof(IToken).GetProperty(filterType));
var right = Expression.Constant(filterValue);
var body = Expression.Equal(left, right);
var predicate = Expression.Lambda<Func<IToken, bool>>(body, t);
return predicate.Compile();
}
用法:
private static void Input_ListTokens(string filterType, string filterValue)
{
Func<IToken, bool> filter = CreateFilter(filterType, filterValue);
foreach (var item in Tokens.Where(filter))
Console.WriteLine(item);
}
答案 1 :(得分:0)
private void Input_ListTokens(string filterType, string filterValue)
{
IEnumerable<string> result = null;
Type t = typeof(IToken);
PropertyInfo f = t.GetProperty(filterType);
if (f!=null)
result = from t in Tokens
where t.GetValue(t)== filterValue
select t.ToString();
}