有没有办法使用反射在结构体实例上设置属性?

56

我试图编写一些代码,在结构体上设置一个属性(重要的是它是结构体的属性),但失败了:

System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);

高度值(由调试器报告)从未设置为任何值-它保持默认值0。

我以前进行过大量有关类的反射,并且这一点很好用。此外,我知道在处理结构时,如果要设置字段,则需要使用FieldInfo.SetValueDirect,但我不知道PropertyInfo的等效方法。

2个回答

86

rectangle的值正在被装箱,但是然后你失去了这个装箱后的值,这就是被修改的值。尝试这样做:

Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;

9
顺便提一下,这是可变值类型的风险之一的很好例子。 - Dan Bryant
2
请确保您不要在循环中执行此操作(或者性能不是问题),特别是如果结构很大的话。 :-) - user541686
1
+1 我也遇到了完全相同的问题。@Dan Bryant - 虽然我同意可变结构体是邪恶的,但我这样做的原因是为了创建一个不可变结构体的工厂类,并且我需要能够设置只读属性。我正在做一些类似于MVC模型绑定子系统的事情,尽管更简单,与Web无关。所以我正在创建不可变结构体,但我只允许在创建时对它们进行一次变异,因此我认为这将避免所有潜在的邪恶。 - Tim Long
2
使用VB.net的人应该使用以下示例: Dim _rectangle As New Rectangle() Dim _propertyInfo As PropertyInfo = GetType(Rectangle).GetProperty("Height") Dim boxed As ValueType = _rectangle _propertyInfo.SetValue(boxed, 5, Nothing) _rectangle = DirectCast(boxed, Rectangle) - Giuseppe
1
@Sнаđошƒаӽ:不,一个值类型值并不是一个对象,尽管它们有继承层次。装箱(Boxing)恰好是分配一个对象来保存值类型值的过程,然后获取对该对象的引用。这里没有足够的空间来讨论值类型和引用类型之间的区别,但我强烈建议您对它们进行研究。 - Jon Skeet
显示剩余3条评论

16

你听说过SetValueDirect吗?他们为什么要创造它呢? :)

struct MyStruct { public int Field; }

static class Program
{
    static void Main()
    {
        var s = new MyStruct();
        s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
        System.Console.WriteLine(s.Field); //Prints 5
    }
}

除了未记录的__makeref方法之外,您可以使用其他方法(请参见System.TypedReference),但它们更加麻烦。


1
请注意:"此 API 不符合 CLS 标准。" - talles
1
在Unity3d中,IL2CPP不支持__makeref()函数。 - Abedron
1
不幸的是,除了不符合CLS标准之外,SetValueDirectTypedReference在结构体中的readonly字段上根本不起作用。在这些情况下,SetValue可以正常工作。 - Eduard Dumitru
@EduardDumitru 我不确定自从你写下评论以来 SetValueDirect 的实现是否有所改变;但是,我刚刚使用它来修改一个 struct 上的 public readonly 字段,并且它起作用了。 - Aly Elhaddad
如果您使用反射来获取原始对象时遇到问题,例如在GetValue上无法调用__makeref,该怎么办? - NetMage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接