FeildInfo.SetValue(object obj,object value) 不改变对象的字段

FeildInfo.SetValue(object obj,object value) make no change to field of object

我一直在尝试使用反射动态分配给结构,以将文件读入命名字符串的结构,但是该过程无法将分配的值加载到结构参数中。 下面的代码有同样的问题,任何关于为什么 testints 字段没有被这个过程更新的见解将不胜感激

using System.Threading;
using System.Reflection;
namespace Reflection_Testing
{
    struct testints
    {
        public int t1;
        public int t2;
        public int t3;
        public int t4;
        public int t5;
    }
    class Program
    {
        static void Main(string[] args)
        {
            testints test1 = new testints();
            

            foreach (var feild in test1.GetType().GetFields())
            {
                feild.SetValue(test1, 17);
            }
            foreach (var feild in test1.GetType().GetFields())
            {
                Console.WriteLine("print test 1");

                Console.WriteLine(feild.GetValue(test1));

            }
        }
    }
}

预期输出:

print test 1
17
print test 1
17
print test 1
17
print test 1
17
print test 1
17

实际输出:

print test 1
0
print test 1
0
print test 1
0
print test 1
0
print test 1
0

首先,我建议在几乎所有情况下避免使用可变结构。如果这是 class,你会没事的,因为不会涉及拳击。

问题是每次你执行这个:

feild.SetValue(test1, 17);

你是 boxing test1 - 在内存中创建一个新对象,它是 test1copy,并传递一个引用该对象到 SetValue 方法。该字段将在该对象上设置 - 但您不再拥有对该对象的引用,因此您永远不会看到它。

如果您装箱 一次,对装箱对象进行所有更改,然后取消装箱或仅对装箱对象调用 GetField,它将给出你期望的输出:

using System;
using System.Reflection;

struct TestInts
{
    public int t1;
    public int t2;
    public int t3;
    public int t4;
    public int t5;
}

class Program
{
    static void Main()
    {
        TestInts test1 = new TestInts();

        // Box the value once
        object boxed = test1;
        foreach (var field in test1.GetType().GetFields())
        {
            field.SetValue(boxed, 17);
        }

        foreach (var field in test1.GetType().GetFields())
        {
            Console.WriteLine($"{field.Name}: {field.GetValue(boxed)}");
        }
    }
}

如果您想要将值返回到您的 test1 变量中,您需要拆箱:

test1 = (TestInts) boxed;

您可以使用下一个代码实现所需的行为(因此在这里将 testints 声明为 class 似乎更合适,请阅读 this and this 指南):

object test1 = new testints();

foreach (var feild in test1.GetType().GetFields())
{
    feild.SetValue(test1, 17);
}
foreach (var feild in test1.GetType().GetFields())
{
    Console.WriteLine("print test 1");

    Console.WriteLine(feild.GetValue(test1));
} 

这将 box test1 and pass it to GetValue/SetValue accepting an object. Also take into account that even without boxing struct's are passed by value(a copy is created and passed to method), so the next will also fail without ref 修饰符:

static void Set(testints t)
{
    t.t1 = 17;
}

var test2 = new testints();
Set(test2);
Console.WriteLine(test2.t1); // prints "0"