C# 如何对对象集合中的单个变量使用函数

C# 如何对对象集合中的单个变量使用函数,c#,function,reflection,C#,Function,Reflection,我正在寻找一种方法,将函数应用于对象集合,每个对象同时具有多个变量,这样我就可以将函数应用于集合中的每个对象,并选择要应用函数的变量。例如: 上课 point{ int x; int y; int z; } 现在让我们假设我希望将函数“展平”应用于这些点的列表,使其中一个变量变为0 其中扁平化可能类似于: flatten<variableName>(List<Point> points){ foreach(var point

我正在寻找一种方法,将函数应用于对象集合,每个对象同时具有多个变量,这样我就可以将函数应用于集合中的每个对象,并选择要应用函数的变量。例如: 上课

point{
   int x;
   int y;
   int z;
}
现在让我们假设我希望将函数“展平”应用于这些点的列表,使其中一个变量变为0

其中扁平化可能类似于:

   flatten<variableName>(List<Point> points){
          foreach(var point in points){
             point.<variableName> = 0;
          }
   }
展平(列表点){
foreach(变量点到点){
点=0;
}
}

有人知道这在c#中是否可能,也许使用某种反射式结构?我知道它可以用Javascript实现,我希望用c#实现,因为它可以防止大量重复代码(注意,我想使用它的实际函数要大得多,并且包含多个子函数)

既然模拟代码希望有人传递变量名,为什么不直接传递lambda呢:

void Flatten(List<Point> points, Action<Point> action)
{
  foreach(var point in points)
  {
    action(point);
  }
}
如果要设置多个值,请传递表达式块:

Flatten(points, point =>
{
  point.x = 0;
  point.y = 0;
});
如果您对使用
列表
(例如,哈希集)以外的序列感兴趣,则只需更改
展平
即可使用
IEnumerable

void Flatten(IEnumerable<Point> points, Action<Point> action)
{
  foreach(var point in points)
  {
    action(point);
  }
}
void展平(IEnumerable points,Action)
{
foreach(变量点到点)
{
行动(点);
}
}

既然模拟代码希望有人传递变量名,为什么不直接传递lambda呢:

void Flatten(List<Point> points, Action<Point> action)
{
  foreach(var point in points)
  {
    action(point);
  }
}
如果要设置多个值,请传递表达式块:

Flatten(points, point =>
{
  point.x = 0;
  point.y = 0;
});
如果您对使用
列表
(例如,哈希集)以外的序列感兴趣,则只需更改
展平
即可使用
IEnumerable

void Flatten(IEnumerable<Point> points, Action<Point> action)
{
  foreach(var point in points)
  {
    action(point);
  }
}
void展平(IEnumerable points,Action)
{
foreach(变量点到点)
{
行动(点);
}
}

虽然我更喜欢肖恩的解决方案,因为它更接近C#并且不需要思考,但对于OP的确切问题,可能的回答是:

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)}");
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
运用系统反思;
命名空间堆栈溢出
{
内部类点
{
公共整数X{get;set;}
公共智力;
公共INTZ;
公共重写字符串ToString()
{
返回$“({X},{Y},{Z})”;
}
}
内部课程计划
{
私有静态空白展平(字符串名称,IEnumerable点)
{
//获取字段或属性
var memberInfo=typeof(点)
.GetMembers()
.式中(m=>m为字段信息| | m为属性信息)
.First(m=>m.Name==Name);
//设定目标值
交换机(memberInfo)
{
案例字段信息字段信息:
foreach(点中的变量点)fieldInfo.SetValue(点,0);
打破
案例属性信息属性信息:
foreach(点中的var point)propertyInfo.SetValue(点,0);
打破
}
}
私有静态void Main(字符串[]args)
{
变量点=新列表
{
新点
{
X=10,
Y=20,
Z=30
},
新点
{
X=100,
Y=200,
Z=300
}
};
Console.WriteLine($”在:{string.Join(;“,points)}之前);
展平(点X的名称),点;
Console.WriteLine($”在:{string.Join(;“,points)}之后);
Console.WriteLine(“------------------------”;
Console.WriteLine($”在:{string.Join(;“,points)}之前);
展平(点的名称,Y),点);
Console.WriteLine($”在:{string.Join(;“,points)}之后);
}
}
}
输出:

之前:(10、20、30);(100200300)

之后:(0,20,30);(0200300)


前:(0,20,30);(0200300)

之后:(0,0,30);(0,0300)

编辑:
改进了处理字段和属性的代码。

虽然我更喜欢Sean的解决方案,因为它更接近C#,并且不需要反射,但对于OP的确切问题,可能的回答是:

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)}");
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
运用系统反思;
命名空间堆栈溢出
{
内部类点
{
公共整数X{get;set;}
公共智力;
公共INTZ;
公共重写字符串ToString()
{
返回$“({X},{Y},{Z})”;
}
}
内部课程计划
{
私有静态空白展平(字符串名称,IEnumerable点)
{
//获取字段或属性
var memberInfo=typeof(点)
.GetMembers()
.式中(m=>m为字段信息| | m为属性信息)
.First(m=>m.Name==Name);
//设定目标值
交换机(memberInfo)
{
案例字段信息字段信息:
foreach(点中的变量点)fieldInfo.SetValue(点,0);
打破
案例属性信息属性信息:
foreach(点中的var point)propertyInfo.SetValue(点,0);
打破
}
}
私有静态void Main(字符串[]args)
{
变量点=新列表
{
新点
{
X=10,
Y=20,
Z=30
},
新点
{
X=100,
Y=200,
Z=300