Я пытаюсь реализовать простой динамический запрос linq для проекта Xamarin.Mac Cocoa с использованием c #.
В WPF я мог бы использовать библиотеку System.Linq.Dynamic для создания динамических запросов linq из строкис чем-то таким простым:
string filter = "type == /"Person"/ && last_name == /"Smith"/";
List<Contact> contacts = ContactList.Where(filter);
Это был быстрый и грязный способ выполнить работу, строки фильтра можно было передать из пользовательского интерфейса.
В Xamarin.Mac IЯ не могу добавить библиотеку System.Linq.Dynamic, поэтому я застрял в поиске решения так же быстро, как и выше.
Я пытался использовать различные лямбда-парсеры, но не нашел такого, которыйсработало еще.Вот пример синтаксического анализатора 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, где запрос для динамического построения запросов без обращения к деревьям выражений?