Как использовать функцию для отдельных переменных в коллекции объектов - PullRequest
1 голос
/ 01 мая 2020

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

point{
   int x;
   int y;
   int z;
}

Теперь предположим, что я sh применил функцию "flatten" к списку этих точек так, чтобы одна из ее переменных стала 0.

Где сглаживание может быть что-то вроде:

   flatten<variableName>(List<Point> points){
          foreach(var point in points){
             point.<variableName> = 0;
          }
   }

Кто-нибудь знает, возможно ли это с c#, возможно, используя какое-то отражение, например структуру? Я знаю, что это может быть сделано в Javascript, и я надеялся сделать это в c#, поскольку это предотвратит много дублирующегося кода (обратите внимание, что реальная функция, для которой я хочу использовать это, гораздо больше и содержит несколько подфункций) ,

Ответы [ 2 ]

6 голосов
/ 01 мая 2020

Поскольку ваш фиктивный код ожидает, что кто-то передаст имя переменной, почему бы просто не передать вместо него лямбду:

void Flatten(List<Point> points, Action<Point> action)
{
  foreach(var point in points)
  {
    action(point);
  }
}

Так что теперь вы можете сказать:

Flatten(points, point => point.x = 0);

Если вы хотите установить более одного значения, а затем передать блок выражения:

Flatten(points, point =>
{
  point.x = 0;
  point.y = 0;
});

Если вы заинтересованы в работе с последовательностями, отличными от List (например, HashSet), тогда просто измените Flatten, чтобы использовать IEnumerable:

void Flatten(IEnumerable<Point> points, Action<Point> action)
{
  foreach(var point in points)
  {
    action(point);
  }
}
2 голосов
/ 01 мая 2020

Хотя мне больше нравится решение Шона, поскольку оно ближе к C# и не требует размышлений, возможный ответ на точный вопрос ОП может быть следующим:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace StackOverflow
{
    internal class Point
    {
        public int X { get; set; }
        public int Y;
        public int Z;

        public override string ToString()
        {
            return $"({X}, {Y}, {Z})";
        }
    }

    internal class Program
    {
        private static void Flatten(string name, IEnumerable<Point> points)
        {
            // Get either fields or properties
            var memberInfo = typeof(Point)
                .GetMembers()
                .Where(m => m is FieldInfo || m is PropertyInfo)
                .First(m => m.Name == name);

            // Set target value
            switch (memberInfo)
            {
                case FieldInfo fieldInfo:
                    foreach (var point in points) fieldInfo.SetValue(point, 0);
                    break;
                case PropertyInfo propertyInfo:
                    foreach (var point in points) propertyInfo.SetValue(point, 0);
                    break;
            }
        }

        private static void Main(string[] args)
        {
            var points = new List<Point>
            {
                new Point
                {
                    X = 10,
                    Y = 20,
                    Z = 30
                },
                new Point
                {
                    X = 100,
                    Y = 200,
                    Z = 300
                }
            };

            Console.WriteLine($"BEFORE: {string.Join("; ", points)}");

            Flatten(nameof(Point.X), points);

            Console.WriteLine($"AFTER: {string.Join("; ", points)}");

            Console.WriteLine("------------------");

            Console.WriteLine($"BEFORE: {string.Join("; ", points)}");

            Flatten(nameof(Point.Y), points);

            Console.WriteLine($"AFTER: {string.Join("; ", points)}");
        }
    }
}

Вывод:

ДО: (10, 20, 30); (100, 200, 300)

ПОСЛЕ: (0, 20, 30); (0, 200, 300)


ДО: (0, 20, 30); (0, 200, 300)

ПОСЛЕ: (0, 0, 30); (0, 0, 300)

РЕДАКТИРОВАТЬ: улучшен код для работы с полями и свойствами.

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