То, что вы пытаетесь сделать, вероятно, неправильно ... Как писал Панайотис, вы можете передать лямбда-выражение методу Pick
. Но я постараюсь, чтобы ваш код работал. Вероятно, у вас проблема XY . Правильным решением было бы понять, что такое проблема Y и что такое решение Y. Вместо этого я дам решение проблемы X.
Теперь то, что вы пытаетесь сделать (помещая имя столбца в string
), называется Dynamic Linq. Мы (где «мы» - большая группа программистов на C #) стараемся не использовать его, потому что это не очень «безопасно», потому что хранение имен столбцов внутри string
делает код трудным для рефакторинга ... Но все же есть ниша ситуаций, где это необходимо. В .NET есть различные библиотеки для работы с Dynamic Linq. В настоящее время разрабатывается System.Linq.Dynamic.Core . Имеет очень практичный
NuGet .
Пример кода:
using System.Linq.Dynamic.Core;
public static class TagPicker
{
public static T Pick<T>(this IQueryable<T> source, string column, string filter) where T : class, new()
{
// Dynamic Linq supports query in the form *columnname = @0*,
// where @0 is the first parameter (and @1 the second and so on)
T result = source.FirstOrDefault(column + " = @0", filter);
if (result is null)
{
// We use reflection to find the column *column* and
// set its value to *filter*. Note that we don't try
// to do a cast, so *column* must be of type *string*
result = new T();
typeof(T).GetProperty(column).SetValue(result, filter);
}
return result;
}
}
, а затем использовать его как:
using (var context = new MyDbContext())
{
var result = context.Products.Pick("ProductName", "Foo");
}
Теперь ... Из любопытства, что, вероятно, предложил Панагиотис:
public static T Pick<T>(this IQueryable<T> source, Expression<Func<T, string>> column, string filter) where T : class, new()
{
Expression<Func<T, bool>> columnFilter = Expression.Lambda<Func<T, bool>>(Expression.Equal(column.Body, Expression.Constant(filter)), column.Parameters);
T result = source.FirstOrDefault(columnFilter);
if (result is null)
{
result = new T();
Expression<Action<T>> assign = Expression.Lambda<Action<T>>(Expression.Assign(column.Body, Expression.Constant(filter)), column.Parameters);
// If you can't compile with the true because you are using an old .NET, remove it
Action<T> assignCompiled = assign.Compile(true);
assignCompiled(result);
}
return result;
}
Используйте это как:
var result = context.Products.Pick(x => x.ProductName, "Foo2");
Обратите внимание, что теперь x.ProductName
больше не является string
, это лямбда-выражение, поэтому оно проверяется компилятором. Вы могли бы иметь:
Expression<Func<Product, string>> selector;
if (somecondition)
{
selector = x => x.ProductName;
}
else
{
selector = x => x.UnitName;
}
var result2 = context.Products.Pick(selector, "Foo2");
или вообще сохраните селекторы в некоторой переменной / выберите правильный селектор любым способом.