Как выбрать определенные свойства в списке

В настоящее время я работаю над требованием, которое использует список и извлекает данные. Но есть изменения, которые мне нужно внести, которых я не получаю.

Теперь у меня есть список элементов, и при выборе пользователя я получаю имена столбцов (случайно), которые являются частью этого списка. Как мне реализовать, потому что во время выполнения я не знаю, сколько имен столбцов я получу.

Ниже приведен пример кода:

class Program
    {
        static void Main(string[] args)
        {
            var students = new List<Student>()
            {
                new Student { Name = "Vijay", Age = 21 , Gender = "M" , Address = "Address_1"},
                new Student { Name = "Ajay", Age = 26 , Gender = "M" , Address = "Address_2"},
                new Student { Name = "John", Age = 21 , Gender = "M" , Address = "Address_3"},
                new Student { Name = "Rob", Age = 42 , Gender = "M" , Address = "Address_4"},
                new Student { Name = "Kohli", Age = 32 , Gender = "M" , Address = "Address_5"}
            };

            var result = students.Select(x => x.Name);  
            // I get result with Name column. That's fine.
            
        }
    }


    public class Student
    {
        public string Name;
        public int Age;
        public string Gender;
        public string Address;
    }

Приведенный выше код является лишь примером того, что я пытаюсь объяснить. Так как students.Select(x => x.Name); даст мне результат, который имеет список Names. Но иногда я могу получать имена столбцов, разделенных запятыми. например Name, Gender или Age, Gender или Name, Address или Address или все имена столбцов.

Expected results:

// When user sends Name & Gender as selected columns
Name, Gender

vijay 26
Ajay  21
Rob   42
...

// When user sends only Address as selected columns
Address

Address_1
Address_2
....

Может ли кто-нибудь помочь мне, как мне создать среду выполнения select, используя доступный список.

заранее спасибо

Я бы порекомендовал переосмыслить, как вы это делаете... если вам случайным образом нужны значения из объекта, вы должны возвращать объект, а затем использовать любое значение, которое вам нужно, на стороне клиента или в интерфейсе.

Jawad 18.12.2020 03:59

Не могли бы вы привести пример ожидаемых данных (для сложного сценария)

Useme Alehosaini 18.12.2020 04:00

обновил ожидаемый результат в вопросе

Vijay 18.12.2020 04:05

Это хрупкий сценарий, реальная жизнь так не работает. Вы должны определить конечную точку для каждого запроса, такого как GetByAddress, GetByNameAndGender и т. д. Если вы все еще хотите сделать, как вы упомянули, сначала вам нужно проанализировать запрос, а затем проанализировать его, а затем с помощью оператора switch или if применить тематический запрос (из-за этого он хрупкий)

Useme Alehosaini 18.12.2020 04:09

Этот вопрос, похоже, не имеет ничего общего с EF, но что касается Linq, вы можете использовать что-то вроде этого: stackoverflow.com/questions/24732724/… Это не будет работать с EF, так как разрешить до SQL. Для EF вам нужно будет использовать условную логику, чтобы решить, какой .Select() оператор вы хотите применить к запросу.

Steve Py 18.12.2020 04:10

Как вы используете результаты? Вернется ли он к пользовательскому интерфейсу... как Json?

ChiefTwoPencils 18.12.2020 04:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
858
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я действительно сделал это некоторое время назад для веб-API. По сути, вы можете использовать Newtonsoft.Json для сериализации вашего типа, сохраняя при этом только те поля\свойства, которые вам нужны.

Во-первых, вам понадобится пользовательский ContractResolver:

    public class SelectiveContractResolver : DefaultContractResolver
    {
        private readonly HashSet<string> properties;

        public SelectiveContractResolver(HashSet<string> selectedProperties)
        {
            properties = selectedProperties;
        }

        protected override JsonProperty CreateProperty
            (
                MemberInfo member,
                MemberSerialization memberSerialization
            )
        {
            var property = base.CreateProperty(member, memberSerialization);

            property.ShouldSerialize = _ =>
                properties
                    .Contains(
                        $"{member.ReflectedType.FullName.ToString()}.{member.Name}"
                        .ToLower());

            return property;
        }
    }

Здесь я специально формирую свои строки, такие как «[полный путь идет здесь].Student.Name» или «[такой же здесь].Student.Gender» и проверяю, было ли выбрано свойство. Это может быть полезно, если вы собираетесь сериализовать сложные типы и вам нужно будет передавать выборки для разных типов вашему Resolver.

Второе, что нужно сделать, и это чисто для оптимизации, создать фабрику, которая кэширует ваши преобразователи, чтобы вам не приходилось каждый раз их пересобирать:

    public class SelectiveContractResolverFactory
    {
        private ConcurrentDictionary<HashSet<string>, IContractResolver>
            cachedResolvers;

        public SelectiveContractResolverFactory()
        {
            cachedResolvers =
                new ConcurrentDictionary<HashSet<string>, IContractResolver>
                    (HashSet<string>.CreateSetComparer());
        }

        public IContractResolver GetResolver
            (
                IEnumerable<string> selectedProperties
            )
        {
            var selectedSet = selectedProperties.ToHashSet();

            if (cachedResolvers.ContainsKey(selectedSet))
                return cachedResolvers[selectedSet];

            var newResolver = new SelectiveContractResolver(selectedSet);
            cachedResolvers[selectedSet] = newResolver;

            return newResolver;
        }
    }

Наконец, давайте применим это к объекту:

var student = new Student { Name = "Vijay", Age = 21 , Gender = "M" , Address = "Address_1"};

var selectedProps = new List<string> {"Student.Name","Student.Age"};

// Obviously, this should be injected as a singleton:
var resolverFactory = new SelectiveContractResolverFactory();

var resolver = resolverFactory.GetResolver(selectedProps);

var selectedResult = JsonConvert.SerializeObject
                     (
                         student,
                         Formatting.None,
                         new JsonSerializerSettings
                         {
                             ContractResolver = resolver
                         }
                     );

И вот так вы получаете аккуратный json-объект с нужными вам свойствами.

Но если вам нужно получить из этого настоящий объект C#, вы можете десериализовать его в ExpandoObject, используя ExpandoObjectConverter:

dynamic filteredStudent = JsonConvert
    .DeserializeObject<ExpandoObject>
    (
        selectedResult,
        new ExpandoObjectConverter()
    );

Хотя, судя по формулировке вопроса, я чувствую, что вы собираетесь возвращать эти данные из своего рода API, поэтому json уже идеально подходит для этого.

Ответ принят как подходящий

Dynamic Linq может вам помочь.

using System.Linq.Dynamic.Core;
var values = new List<string> { "Age", "Gender" };

var columns = "new {" + string.Join(",", values) + "}";

var result = students.AsQueryable().Select(columns);

foreach (var x in result)
    Console.WriteLine(x);

Выход:

{ Age = 21, Gender = M }
{ Age = 26, Gender = M }
{ Age = 21, Gender = M }
{ Age = 42, Gender = M }
{ Age = 32, Gender = M }

Имейте в виду, что вы получаете анонимный тип. А как вы будете с ним работать дальше — это еще вопрос.

Мне нужно экспортировать эти данные в excel..!! Даже сейчас worksheet.Cells["A1"].LoadFromCollection(resultList, true) где я получаю исключение

Vijay 18.12.2020 05:59

Я должен отметить, что этот подход смехотворно медленный. Всего 1000 итераций по этому исходному списку из 5 студентов занимают почти 2 полных секунды на приличной машине. При 100 тыс. итераций мне пришлось ждать 1 минуту 41 секунду. Если я не пропускаю какую-то оптимизацию, ее не следует использовать ни в одной системе, которая ожидает приличную нагрузку. Для сравнения, мой подход занимает около 2,131 секунды со 100 000 итераций.

user4182984 18.12.2020 07:11

Другие вопросы по теме