使用反射在C#中设置一个具有{get;}属性的属性

3

我有一个来自第三方库的类,其中有一个只读属性叫做Name。以下是该类的代码:

public class Person
{
    public string Name {get;}
}

我想使用反射或其他合适的方法来设置Name属性的值,但我不知道该属性是如何实现的。具体而言,我不知道它是否有一个类似于这样的后备字段:
private string m_name;

或者如果它的实现是这样的:
public string Name {get; private set;}

如何在这种情况下设置Name属性的值?

哎呀,今天我学到了... - maccettura
1
@Vahid...如果它是一个自动实现的属性,那么Name的实例变量将是name。 - Chris Catignani
1
@ChrisCatignani 在当前的Roslyn版本中,后备字段名称为<Name>k__BackingField - yaakov
1
Mono.Reflection有一个扩展方法GetBackingField(),用于PropertyInfo,它返回FieldInfo。这仅适用于自动属性。由于您说它是第三方库,很有可能它不是自动属性,您就没那么幸运了。 - Mr Anderson
1
还有可能它没有支持字段 - 名称在getter中以某种方式生成。你可以反编译DLL并查看getter的代码,但我不知道是否有自动化的方法来实现这一点。 - D Stanley
显示剩余8条评论
1个回答

6
你需要获取属性后备字段的FieldInfo实例并调用SetValue()方法。 Mono.Reflection库(在软件包管理器中可用)将帮助您找到后备字段。
如果属性是自动属性,则可以在PropertyInfo实例上调用GetBackingField()扩展方法。
否则,您将不得不像这样分解getter的MethodInfo IL:
var instructions = yourProp.GetGetMethod().GetInstructions();

这将为您提供该方法的IL指令列表。如果它们看起来像这样:
Ldarg0
Ldfld    (Backing Field)
Ret

然后第二条指令将给你后备字段。在代码中:

if (instructions.Count == 3 && instructions[0].OpCode == OpCodes.Ldarg_0 && instructions[1].OpCode == OpCodes.Ldfld && instructions[2].OpCode == OpCodes.Ret)
{
    FieldInfo backingField = (FieldInfo)instructions[1].Operand;
}

否则,该属性可能是计算的并且没有支持字段。

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