为什么在 C# 7.2 中具有 "in" 参数修饰符的 List<> 仍然可以修改

Why can you still modify a List<> when it has the "in" parameter modifier in C# 7.2

本周早些时候,C# 7.2 发布了 "in" 参数修饰符的新功能,请参阅发行说明 here

发行说明中提供的详细信息是:"The in modifier on parameters, to specify that an argument is passed by reference but not modified by the called method."

目前还没有很多关于这个新功能的文档,所以我一直在尝试。对于基本类型,似乎按预期工作,并阻止访问对象属性。但是,对于列表,您仍然可以调用方法来修改列表(即添加、删除、反转),并且您实际上可以直接修改元素。

    static void Main(string[] args)
    {
        var test = new List<int>();
        test.Add(5);
        Console.WriteLine(test[0]);
        TestMethod(test);
        Console.WriteLine(test[0]);
    }

    public static void TestMethod(in List<int> myList)
    {
        myList[0] = 10;
        myList.Add(7);
        myList.Remove(2);
    }

我的问题是,为什么使用"in"参数修饰符仍然可以修改集合?

in 修饰符仅限制对引用的赋值,但 List<T> 仍然是可访问和可变的。基本上它的工作方式类似于 ref readonly.

你做不到myList = new List<int>

documentation 中的这些要点真正阐明了 in 修饰符的意图:

There are several ways in which the compiler ensures that the read-only nature of an in argument is enforced. First of all, the called method can't directly assign to an in parameter.

好的,这意味着我们不能这样做:

public void Something(in Point3D point1)
{
    point1 = new Point3D(); // not allowed
}

It can't directly assign to any field of an in parameter.

好的,这意味着我们不能这样做:

public void Something(in Point3D point1)
{
    point1.X = 10; // not allowed
}

In addition, you cannot pass an in parameter to any method demanding the ref or out modifier.

好的,这意味着由于显而易见的原因我们不能在下面做同样的事情,因为我们调用的方法可以设置引用,这将打破上面的第一条规则:

public void Something(in Point3D point1)
{
    SomethingElse(ref point1); // not allowed
}

public void SomethingElse(ref Point3D pointAnother)
{}

The compiler enforces that the in argument is a readonly variable. You can call any instance method that uses pass-by-value semantics. In those instances, a copy of the in parameter is created. Because the compiler can create a temporary variable for any in parameter, you can also specify default values for any in parameter.

所以我从上面收集到的是你可以传递一个 List<T> 并且被调用的方法将能够向它添加项目但是它不能为它分配另一个列表或改变它的领域。

总结

Why can you still modify a List<> when it has the “in” parameter modifier in C# 7.2

你可以这样做,因为你没有违反任何规则。