C#无法修改Struct的返回值,因为它不是变量

using UnityEngine;
using System.Collections;
using System.Xml.Linq;
using UnityEditor;
using System;

public class NewBehaviourScript : MonoBehaviour {

    struct MVec3{
        public float x;
        public float y;
        public float z;
    }

    class CTest{
        
        public MVec3 posx;
        public MVec3 pos { set; get; }//等同于下面的写法->

        /*MVec3 dv = new MVec3 ();
        public MVec3 pos{
            set{ dv = value; }
            get{ return dv;}
        }*/

    }

    CTest otest;

    // Use this for initialization
    void Start () {
        otest = new CTest ();

        otest.pos.x = 10;
        otest.posx.x = 123;
        gameObject.transform.position.x = 10;

        Debug.Log ("ot.pos.x={0}" + otest.posx.x);

    }
    // Update is called once per frame
    void Update () {
        Vector3 vec3 = gameObject.transform.position;
    }
}

编译时出现如下错误:

可以看到34行和36行都出现了编译错误,而35行则正确编译。原因分析:

关于C#堆栈文章
C#中,reference类型变量存储在堆上,value类型存储在栈上(指通常声明的局部变量或属性,如果在引用类型例如Class中声明的字段会随Class在堆中)。pos, posx, position都是值类型,为什么会有不同的编译结果呢。区别在于 pos, position是属性,posx是字段。具体分析如下:

32行:new了一个引用类型CTest的对像otest,这时在堆上为对象分配了一片内存,内存大小为pos的三个float和posx的三个float。

34行:由于pos是一个属性,otest.pos将调用属性的get方法,方法的调用是使用栈来进行的,get方法在栈上分配一个临时变量temp来返回pos的的值。即otest.pos返回了一个分配在栈上的临时变量的地址,而otest.pos.x = 10则是试图对栈上临时变量的X进行赋值。这个操作并非不合法,然而是没有意义的,于是编译器就阻止了我们的这个无意义操作,以避免隐患。同理36行。

明白了这个,就容易理解35行为什么是正确的了。otest.posx是一个正常的取地址操作,表示取出otest所在堆内存中的posx变量的地址,这个地址是对象的堆内存中的。

otest.posx.x = 10则是修改堆内存中posx的x的值。

posted @ 2021-08-26 11:38  yassine  阅读(561)  评论(0编辑  收藏  举报