我已经看到了各种问题并回答了我们可以使用这样的反射来调用私有的setter:
Is it possible to get a property's private setter through reflection?
但是我有一些代码有一个我需要设置的属性,但因为没有setter,我不能添加一个setter,因为这不是我的代码。在这种情况下,有没有办法以某种方式使用反射设置值?
答案 0 :(得分:14)
我不建议在您的应用程序上执行此操作,但出于测试目的,它可能有用...
假设你有:
public class MyClass
{
public int MyNumber {get;}
}
如果出于测试目的,你可以这样做,我不建议在运行时代码中使用它:
var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(anIstanceOfMyClass, 3);
答案 1 :(得分:7)
你必须记住,属性只是一对方法的语法糖。一个方法(getter)返回属性类型的值,一个方法(setter)接受属性类型的值。
并不要求getter和setter实际获取或设置任何内容。他们只是方法,所以他们可以做任何事情。唯一的要求是getter返回一个值。从外面看,你无法确定是否有支持领域。每次调用时都可以计算getter。它可能基于其他属性。
所以,不,一般来说没有任何方法可以“设置”没有设置器的属性。
答案 2 :(得分:0)
在@abyte0的回答中添加一个实际用例。
一些库利用反射来设置属性。例如,请参阅来自 https://github.com/natemcmaster/CommandLineUtils 的示例代码:
using System;
using McMaster.Extensions.CommandLineUtils;
public class Program
{
public static int Main(string[] args)
=> CommandLineApplication.Execute<Program>(args);
[Option(Description = "The subject")]
public string Subject { get; } = "world";
[Option(ShortName = "n")]
public int Count { get; } = 1;
private void OnExecute()
{
for (var i = 0; i < Count; i++)
{
Console.WriteLine($"Hello {Subject}!");
}
}
}
在幕后,这个语法是用 this code 实现的:
public static SetPropertyDelegate GetPropertySetter(PropertyInfo prop)
{
var setter = prop.GetSetMethod(nonPublic: true);
if (setter != null)
{
return (obj, value) => setter.Invoke(obj, new object?[] { value });
}
else
{
var backingField = prop.DeclaringType.GetField($"<{prop.Name}>k__BackingField", DeclaredOnlyLookup);
if (backingField == null)
{
throw new InvalidOperationException(
$"Could not find a way to set {prop.DeclaringType.FullName}.{prop.Name}. Try adding a private setter.");
}
return (obj, value) => backingField.SetValue(obj, value);
}
}
这里的实际价值是让代码表明设置值的唯一方法是通过命令行调用。这是允许的:hello.exe -s world
但这不是:Subject = "some other value";