我正在尝试使用c#为Xamarin.Mac Cocoa项目实现简单的动态linq查询。
在WPF中,我可以使用System.Linq.Dynamic库从字符串创建动态linq查询,就像这样简单:
string filter = "type == /"Person"/ && last_name == /"Smith"/";
List<Contact> contacts = ContactList.Where(filter);
这是完成工作的一种快速而肮脏的方法,可以从UI传递过滤器字符串。
在Xamarin.Mac中,我无法添加System.Linq.Dynamic库,因此我一直在寻找与上述解决方案一样快的解决方案。
我尝试使用各种lambda解析器,但是还没有找到一个可行的解析器。这是Microsoft.CodeAnalysis.CSharp.Scripting解析器的示例,但是我没有足够的经验来知道如何实现此功能:
private async Task<List<Contact>> QueryContacts()
{
try
{
var contactFilter = search.searchstring;
var lambdaParser = new LambdaParser();
var context = new Dictionary<string, object>();
context["contact"] = (Func<Contact>)(() => new Contact());
return App.ContactList.Where(lambdaParser.Eval(contactFilter, context));
}
catch (Exception ex)
{
Err(ex, "QueryContacts");
}
return App.ContactList;
}
这是我尝试过的另一个:
private async Task<List<Contact>> QueryContacts()
{
try
{
string query = search.searchstring;
var externals = new Dictionary<string, object>();
externals.Add("Contacts", App.ContactList.AsQueryable());
var expression = DynamicExpression.Parse(typeof(IQueryable<Contact>), query, new[] { externals });
var result = App.ContactList.AsQueryable().Provider.CreateQuery(expression);
return (List<Contact>)result;
}
catch (Exception ex)
{
Err(ex, "QueryContacts");
}
return App.ContactList;
}
这是我尝试过的最新游戏。这个似乎已经接近了,但是我收到了“指定的参数数量与预期数量不匹配”的异常:
private async Task<List<Contact>> QueryContacts()
{
try
{
string query = search.searchstring; // "id == 1"
var p = Expression.Parameter(typeof(Contact), "Contact");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda<Contact, bool>(query, new[] { p });
var result = e.Compile().DynamicInvoke(App.ContactList.ToArray());
return (List<Contact>)result;
}
catch (Exception ex)
{
Err(ex, "QueryContacts");
}
return App.ContactList;
}
在这种情况下,search.searchstring的值很简单:id ==1。此行上引发了异常:
var result = e.Compile().DynamicInvoke(App.ContactList.ToArray());
如果有帮助,以下是异常的堆栈跟踪:
at System.Reflection.MonoMethod.ConvertValues (System.Reflection.Binder binder, System.Object[] args, System.Reflection.ParameterInfo[] pinfo, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) [0x00016] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.193/src/Xamarin.Mac/mcs/class/corlib/System.Reflection/MonoMethod.cs:331
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00011] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.193/src/Xamarin.Mac/mcs/class/corlib/System.Reflection/MonoMethod.cs:293
at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.193/src/Xamarin.Mac/mcs/class/referencesource/mscorlib/system/reflection/methodbase.cs:229
at System.Delegate.DynamicInvokeImpl (System.Object[] args) [0x000e1] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.193/src/Xamarin.Mac/mcs/class/corlib/System/Delegate.cs:461
at System.MulticastDelegate.DynamicInvokeImpl (System.Object[] args) [0x00008] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.193/src/Xamarin.Mac/mcs/class/corlib/System/MulticastDelegate.cs:67
at System.Delegate.DynamicInvoke (System.Object[] args) [0x00000] in /Library/Frameworks/Xamarin.Mac.framework/Versions/4.4.1.193/src/Xamarin.Mac/mcs/class/corlib/System/Delegate.cs:406
at WealthBoxAddon.ViewController+<QueryContacts>d__95.MoveNext () [0x00059] in /Users/chrisbrowning/Projects/WealthBoxAddon/WealthBoxAddon/ViewController.cs:548
更糟糕的是,我可以使用表达式树,但是其中有很多代码,而且调试起来并不容易。
有没有一种解决方案可以采用字符串并将其用于linq中,而linq中的查询无需借助表达式树即可动态构建查询?