2016-07-14 5 views
2
public class Sample 
{ 
public int Id { get; set; } 
public string Description { get; set; } 
public DateTime EffectiveDate { get; set; } 
} 

IEnumberable<Sample> sampleList; 
//Populate the list 

Теперь я хочу отфильтровать список несколько раз с помощью свойства «ИД», иногда «Описание». Просто хочу передать имя свойства (filterColumn) и значение свойства (filterValue) как строки.C# Linq Filter IEnumerable dynamic property and value

Я попытался следующие:

IEnumerable<Sample> result = sampleList.Where(x => x.GetType().GetProperty(filterColumn).Name == filterValue); 

И

string whereQuery = string.Format(" {0} = \"{1}\"", filterColumn, filterValue); 
IEnumerable<Sample> result = sampleList.AsQueryable().Where(whereQuery); 

Второй вариант работает, если я передать filterColumn как "Описание", но бросает incomptable оператор '=' между строкой и межд ошибка, когда «Id» передается как filterColumn и некоторый filterValue как «1».

Цените любую помощь. Спасибо

+0

Ваш первый проверяет, что имя * * * совпадает с указанным значением свойства. Вам нужно вызвать '.GetValue (x, null)' в PropertyInfo ...а затем вы хотите использовать 'Equals', а не' == '. –

+0

Почему вы делаете '.AsQueryable()'? – Enigmativity

ответ

1

Ваш первый подход может работать. Расширяясь в комментарии Джона Скита, вот скорректированное утверждение.

IEnumerable<Sample> result = sampleList.Where(
    x => x.GetType().GetProperty(filterColumn).GetValue(x, null).Equals(filterValue) 
); 

Чтобы создать небольшой контекст вокруг этого, вам придется учитывать разные типы данных. Вы можете сделать это как минимум двумя способами: использовать общий метод или использовать тип данных объекта. Для иллюстративных целей я буду использовать объектный подход.

public IEnumerable<Sample> GetFiltered(
    IEnumerable<Sample> samples, string filtercolumn, object filtervalue 
{ 
    return samples.Where(
     x => x.GetType().GetProperty(filtercolumn).GetValue(x, null).Equals(filtervalue) 
    ); 
} 

IEnumberable<Sample> sampleList; 

var byId = GetFiltered(sampleList, "Id", 100); 
var byDescription = GetFiltered(sampleList, "Description", "Some Value"); 

Этот пример не очень безопасно, так как нет типа проверки, чтобы убедиться, что значение свойства будет иметь тот же тип данных, которые вы передаете в. Так, например, ничто не мешает вам передать «Описание »и 100 в качестве параметров. Вы не можете провести значимое сравнение целого числа с строкой, чтобы вы всегда получали пустой результат. Метод Equals не генерирует исключение, он просто видит, что оба объекта различны. Как указал Джон, вы всегда будете использовать Equals в этом случае, а не оператор «==». Метод Equals предназначен для сравнения контента, тогда как «==» сравнивает ссылки. Пример:

Console.WriteLine(12 == 12); 
// True 

object a = 12; 
object b = 12; 

Console.WriteLine(a == b); 
// False - because, due to boxing, a and b are separate objects 
// that happen to contain the same value. (Check out "boxing" 
// if this doesn't make sense.) 

Console.WriteLine(a.Equals(b)); 
// True - because the Equals method compares content (value) 

Также обратите внимание, что при использовании оператора «==» строки имеют некоторое специальное поведение. Важно помнить, что существует разница между ссылками (контейнерами) и контентом. Вы хотите сравнить контент, а это означает Equals. (Я заметил, что окно Immediate в Visual Studio противоречит его результатам относительно строк при использовании «==». Я подозреваю, что это связано с тем, что ссылки на строки могут быть, но не всегда оптимизированы в этом окне.)

Вы заявляете, что работает ваш второй подход. Я не видел этот тип строки фильтра в стандартном методе IEnumerable.Where. Поэтому я предполагаю, что вы используете некоторые расширения. Ваш пример не работает, как показано. Класс DataTable использует строки фильтра, которые соответствуют вашему использованию. В общем случае строка фильтра должна быть построена по-разному на основе типа данных. Например, для строки требуются кавычки (которые у вас есть), но целочисленное значение не использует кавычки.

1

Другой вариант, который у вас есть, - это создать словарь с требуемыми операциями.

public IEnumerable<Sample> GetFiltered(
    IEnumerable<Sample> samples, string property, string value) 
{ 
    var map = new Dictionary<string, Func<string, Func<Sample, bool>>>() 
    { 
     { "Description", v => s => s.Description == v }, 
     { "Id", v => s => s.Id == int.Parse(v) }, 
    }; 
    return samples.Where(map[property](value)); 
} 

Преимущества здесь состоит в том, что вы можете выполнить более сложное сравнение, такие как добавление пользовательских фильтров диапазонов значений, или те, которые содержат более одного свойства.