C# 如何使用反射正确设置调用链中的值类型
因此,我正在编写一个解析器,它使用xml文档创建一组对象并填充它们的属性。我希望用户能够使用属性放置类似position.x=“5”的属性,并将x位置设置为5 我的问题是值类型字段可以很容易地用下面的代码修改,因为我可以修改原始值,但是值类型属性返回一个副本,该副本必须修改并重新分配给源对象。关于如何处理值类型属性有什么想法吗 示例:position是一个属性Vector2类型的结构。MyObject.position.x=5将不起作用,因为在position上调用SetValue将 创建一个临时位置,并将x设置为5。因此,附着到对象的实际位置将不会获得值5。如果我执行MyObject.position=new Vector2(5,0),我会将位置设置为5,0,因为我不会尝试改变位置元素,而是将整个值指定给位置 注意:我编写了一些扩展方法,因此“GetValue”对成员信息有效C# 如何使用反射正确设置调用链中的值类型,c#,reflection,properties,value-type,C#,Reflection,Properties,Value Type,因此,我正在编写一个解析器,它使用xml文档创建一组对象并填充它们的属性。我希望用户能够使用属性放置类似position.x=“5”的属性,并将x位置设置为5 我的问题是值类型字段可以很容易地用下面的代码修改,因为我可以修改原始值,但是值类型属性返回一个副本,该副本必须修改并重新分配给源对象。关于如何处理值类型属性有什么想法吗 示例:position是一个属性Vector2类型的结构。MyObject.position.x=5将不起作用,因为在position上调用SetValue将 创建一个临
private bool SetAttributeValue(string text,object obj,MemberInfo setter)
{
BuildParseMethods();
if (!TryParseAttribute(text, setter.GetMemberType(), out object value))
return false;
setter.SetValue(obj, value);
return true;
}
private void SetChainAttribute(XmlAttribute attribute,object instance)
{
object target = instance;
MemberInfo[] bindings = null;
string[] parts = attribute.Name.Split('.');
Type type = instance.GetType();
for (int i = 0; i < parts.Length; i++)
{
bindings = type.GetMember(parts[i], BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetField | BindingFlags.SetProperty | BindingFlags.IgnoreCase);
if (bindings == null || bindings.Length == 0)
{
Debug.LogError($"Unable to find element {i} of {attribute.Name}");
return;
}
if (i < parts.Length - 1)
{
target = bindings[0].GetValue(target);
type = target != null ? target.GetType() : bindings[0].GetType();
}
}
SetAttributeValue(attribute.Value, target, bindings[0]);
}
private bool SetAttributeValue(字符串文本、对象对象、成员信息设置器)
{
BuildParseMethods();
if(!TryParseAttribute(text,setter.GetMemberType(),out对象值))
返回false;
setter.SetValue(对象,值);
返回true;
}
私有void SetChainAttribute(XmlAttribute属性,对象实例)
{
对象目标=实例;
MemberInfo[]绑定=null;
string[]parts=attribute.Name.Split('.');
Type Type=instance.GetType();
对于(int i=0;i
C#中的结构应该是不可变的,因此当从属性/方法返回结构作为参数传递时,编译器会创建结构的副本,以防止对其进行修改
正如您可能已经意识到的,您可以设置Position
属性来覆盖整个Vector2
,以便在反射代码中遵循该路径:
var myObj = new MyObject();
myObj.Position = new Vector2();
// This produces error CS1612 Cannot modify the return value of 'MyObject.Position' because it is not a variable
myObj.Position.X = 5;
// Workaround:
// Use reflection to set Position instead of Position.X
var prop = myObj.GetType().GetProperty("Position");
prop.SetValue(myObj, Activator.CreateInstance(prop.PropertyType, 5));
Activator.CreateInstance
根据提供的参数找到要调用的Vector2
的正确构造函数
另一种方法是在MyObject
上使用装箱结构:
Boxed struct可以在复制问题上“生存”,但可能存在性能权衡,您必须能够访问
Vector2
的源代码。我已经读过几遍了,有点不清楚问题是什么,它与代码的关系如何,或者您正在尝试做什么(尽管可能只有我一个人)@MichaelRandall我添加了一些代码,并试图通过一个示例更好地阐明它。
interface IVector2
{
int X { get; set; }
}
struct Vector2 : IVector2
{
}
class MyObject
{
public IVector2 BoxedPosition { get; set; }
}