C# 如何使用反射正确设置调用链中的值类型

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将 创建一个临

因此,我正在编写一个解析器,它使用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”对成员信息有效

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; }
}