C# 中结构体类型作为类属性时,无法修改其属性值

今天遇到个问题, 结构体通过属性访问修改的时候会出现以下编译错误

class Program
{
    static void Main(string[] args)
    {
        Transform t = new Transform();
        t.v.x = 1; // 编译不通过
        t.ShowV();
        Console.Read();
    }
}

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

class Transform
{
    public Vector1 v { get; set; }
    public void ShowV()
    {
        Console.WriteLine(v.x + "..." + v.y + "..." + v.z);
    }
}

原因是结构体类型是值类型, 使用 public Vector1 v { get; set; } 访问时 t.v , 实际上调用的是 public Vector1 GetVector1() 由于是值类型, 实际上是传递的 v的副本 , 那么 t.v.x = 1; 就是无意义的了, 因为是修改的副本, 不会改源数据, VS编辑器就直接编译不通过了。同理在集合的List<结构>等方法中使用索引访问结构的成员时实际上也是访问了结构 this[int index]方法,不能使用变量[0].结构属性 = 1这种方式修改结构的集合值。

但是呢, 如果将 public Vector1 v { get; set; } 改成 public Vector1 v;就没问题了, 正常编译和执行, 也可以正确的修改数据, 因为更改后 t.v 直接调用了其字段, 而不是通过方法返回的, 所以也不是其副本.


另外, 这里要特别说明一下

  • 类/结构体的默认访问修饰符是internal
  • 方法的默认修饰符是private, 其中构造方法默认public
  • 字段(field),其默认访问修饰符是private
  • 属性(Property)的默认访问修饰符是public
public class Transform
{
    public Vector1 v;
    public void ShowV()
    {
        Console.WriteLine(v.x + "..." + v.y + "..." + v.z);
    }
}

上例中, 将 class Transform 修改成 public class Transform 那么 public Vector1 v; 就会报错, 原因是 Transform.v是public, 而Vector1的可访问性是internal, public访问internal就会出现错误, 反过来就不会出错

修改方法是修改 public struct Vector1 或者 internal Vector1 v; 即可, 达到了可访问性一致.

此处评论已关闭