设置实例 属性 不带 Setter
Set Property of Instance without Setter
假设我有一个 class 和一个如下所示的界面:
[Serializable]
public class MyClass : IClass
{
public int Prop => 42;
}
public interface IClass
{
int Prop { get; }
}
如您所见,没有 Setter。但我希望使用反射来更改 Prop 属性 但我似乎做不到。这是我目前拥有的:
var property = typeof(MyClass).GetProperty("Prop", BindingFlags.Instance | BindingFlags.Public);
property.SetValue(instaneOfClass, 31);
我不断收到此错误:System.ArgumentException: Property set method not found.
这行不通吗?如何在不使用 setter 的情况下设置 属性?
自动实现的属性具有名为 <PropName>k__BackingField
的支持字段。
在您的情况下,您将像这样访问此支持字段:
var property = typeof(MyClass).GetField("<Prop>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
property.SetValue(instanceOfClass, 31);
请注意,我调用 GetField()
而不是 GetProperty()
,并使用 BindingFlags.NonPublic
而不是 BindingFlags.Public
,因为支持字段是私有的。
但是,由于这是一个表达式主体成员(lambda 语法),因此不会生成支持字段。 getter 不依赖于另一个成员,而是 getter returns 给定表达式的结果,编译器不需要生成支持字段。
使用显式 getter 实现您的 属性 将生成一个支持字段,上面的代码将起作用。
public class MyClass : IClass
{
public int Prop { get; } = 42;
}
如果您指定 getter,您将拥有一个包含 属性 名称的编译器生成字段。然后可以使用反射(GetFields,SetValue)修改这个字段的值:
public class Foo {
public Foo() => Bar = 42;
public int Bar { get; }
static void Main() {
var f = new Foo();
Console.WriteLine(f.Bar); // ==> 42;
f.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic).First(x => x.Name.Contains("Bar")).SetValue(f, 43);
Console.WriteLine(f.Bar); // ==> 43;
}
}
它不适用于您示例中的计算 属性。
假设我有一个 class 和一个如下所示的界面:
[Serializable]
public class MyClass : IClass
{
public int Prop => 42;
}
public interface IClass
{
int Prop { get; }
}
如您所见,没有 Setter。但我希望使用反射来更改 Prop 属性 但我似乎做不到。这是我目前拥有的:
var property = typeof(MyClass).GetProperty("Prop", BindingFlags.Instance | BindingFlags.Public);
property.SetValue(instaneOfClass, 31);
我不断收到此错误:System.ArgumentException: Property set method not found.
这行不通吗?如何在不使用 setter 的情况下设置 属性?
自动实现的属性具有名为 <PropName>k__BackingField
的支持字段。
在您的情况下,您将像这样访问此支持字段:
var property = typeof(MyClass).GetField("<Prop>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
property.SetValue(instanceOfClass, 31);
请注意,我调用 GetField()
而不是 GetProperty()
,并使用 BindingFlags.NonPublic
而不是 BindingFlags.Public
,因为支持字段是私有的。
但是,由于这是一个表达式主体成员(lambda 语法),因此不会生成支持字段。 getter 不依赖于另一个成员,而是 getter returns 给定表达式的结果,编译器不需要生成支持字段。
使用显式 getter 实现您的 属性 将生成一个支持字段,上面的代码将起作用。
public class MyClass : IClass
{
public int Prop { get; } = 42;
}
如果您指定 getter,您将拥有一个包含 属性 名称的编译器生成字段。然后可以使用反射(GetFields,SetValue)修改这个字段的值:
public class Foo {
public Foo() => Bar = 42;
public int Bar { get; }
static void Main() {
var f = new Foo();
Console.WriteLine(f.Bar); // ==> 42;
f.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic).First(x => x.Name.Contains("Bar")).SetValue(f, 43);
Console.WriteLine(f.Bar); // ==> 43;
}
}
它不适用于您示例中的计算 属性。