【问题标题】:Can I call the "Set" method of a struct property using reflection?我可以使用反射调用结构属性的“设置”方法吗?
【发布时间】:2020-04-08 17:45:40
【问题描述】:

我定义了一个结构:

public struct Settable
{
     public string SettableProperty { get; set; }
}

我可以用通常的方式设置结构的属性值:

s.SettableProperty = "Abc";

但是,当我创建一个方法来尝试通过反射设置属性时:

public T CreateWithValue<T>(string propName, string propValue)
{
    var retObj = Activator.CreateInstance<T>();
    var prop = typeof(T).GetProperty(propName);

    var _ = prop.SetMethod.Invoke(retObj, new object[] { propValue});
    return retObj;
}

...这样称呼它:

var x = CreateWithValue<Settable>("SettableProperty", "Abc");

...我最终将SettableProperty 初始化为其默认值null。 (不抛出异常。)

请注意,如果我将 Settable 定义为 class 而不是 struct,则该值将按预期设置。

是否可以使用反射设置结构属性?

【问题讨论】:

  • 附带说明:拥有可变结构通常是一个糟糕的主意;如果我对此进行投票,我会强烈建议将public readonly struct Settable 与通过构造函数设置的get-only 属性一起使用。
  • @MarcGravell - 注意。这是测试代码,我最终会得到许多我希望能够轻松进行值比较的结构,Assert.AreEqual 可以用结构做。我还想让它们可变以提高测试灵活性。您是否建议将它们设为类并使用不同的比较方法,或者这似乎是使用可变结构的合理时机?
  • 那是很主观的事情;我确实知道的是,我已经帮助了很多与可变结构作斗争的人 - 他们造成了很多混乱
  • Welp,花了 5 个小时,但我遇到了与可变结构相关的问题。已采纳建议。
  • 但是想想你在这个过程中学到了多少! (玻璃半满等)

标签: c# .net reflection f# system.reflection


【解决方案1】:

这里的问题是retObjT,一个值类型,但Invoke 接受object。这个 boxes 值,它在堆上(在盒子内)创建一个孤立的副本,然后您对其进行变异。 retObj 中的本地副本不会受到任何影响,因为它是一个完全断开的值副本。

请考虑:

public T CreateWithValue<T>(string propName, string propValue)
{
    object retObj = Activator.CreateInstance<T>();
    var prop = typeof(T).GetProperty(propName);

    prop.SetMethod.Invoke(retObj, new object[] { typedValue });
    return (T)retObj;
}

这将创建 earlier 框,并将其拆箱以获得修改后的值。然而,它的效率不是很高(注意:我没有添加任何低效率;当使用带有值类型的object API 时,低效率是固有的)。如果您愿意变得更脏,您可以删除分配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多