提问人:Patrick Cerny 提问时间:7/24/2023 最后编辑:CharliefacePatrick Cerny 更新时间:7/24/2023 访问量:147
为什么“in”关键字允许 C# 属性的突变?
Why does the "in" keyword allow mutation of properties C#?
问:
我目前正在研究一个函数,其中传递了一个对象(自写类型),并且不得在被调用的函数中发生突变/更改。这里有一个简单的例子。Catalog
public override bool Migrate(in Catalog fromCatalog)
{
fromCatalog.SupplierId = 1; //works, but why
}
我想严格破坏这种行为,并不允许改变传递对象的任何属性。
答:
2赞
Volodymyr
7/24/2023
#1
因为 in 修饰符仅适用于变量(在本例中为参数)。它可以防止参数更改其值以引用其他对象。
public bool Migrate(in Catalog fromCatalog)
{
/* Error CS8331 Cannot assign to variable 'fromCatalog'
or use it as the right hand side of a ref assignment
because it is a readonly variable */
fromCatalog = new Catalog();
fromCatalog.SupplierId = 1;
}
并创建对象的浅拷贝,以便您不会更改传递的对象(在类中)中的任何内容
例:
public Catalog CreateACopy()
{
Catalog obj = (Catalog)this.MemberwiseClone();
// and other...
return obj;
}
利用率:
public class Program
{
private static void Main()
{
Catalog catalog = new Catalog();
new Program().Migrate(catalog.CreateACopy());
}
public bool Migrate(in Catalog fromCatalog)
{
fromCatalog.SupplierId = 1;
}
}
评论
3赞
Jon Skeet
7/24/2023
“因为 in 修饰符仅适用于对象” - 不,它适用于参数,而不是对象。
0赞
Volodymyr
7/24/2023
我想说 in 修饰符不允许传递的变量更改此方法中的引用,对吗?
3赞
Jon Skeet
7/24/2023
有点,虽然我不是这样表达的。但是,了解变量(在本例中为参数)和对象之间的区别非常重要。如果修饰符真正应用于对象,它将阻止对对象本身进行更改,而这正是它不做的。它可以防止参数更改其值以引用其他对象。in
1赞
Andrew Williamson
7/24/2023
再加上 Jon 的评论,编译器很难准确地阻止对对象本身进行更改。禁止直接成员赋值很容易,但编译器还必须有一种方法来区分哪些方法会改变对象,以便防止它们被调用。这并不像“任何改变对象的方法”那么简单,因为某些方法可能只是填充缓存
1赞
JonasH
7/24/2023
#2
它之所以有效,是因为 Catalog 具有可写属性。C# 没有常量值的概念,例如 C++。所以只是另一个值,你可以传递,调用方法,设置属性等。fromCatalog
但这并不意味着编写这样的代码没有多大意义。关键字最有用的是避免值类型的副本。但是,如果值类型是可变的,编译器无论如何都必须创建一个防御性副本,只是为了防止原始对象被修改。in
因此,一般建议是使您的值类型不可变/只读,这样可以避免该问题。另请参阅为什么可变结构是邪恶的。
评论
SupplierId
in
只是表示编译器阻止了,而不是fromCatalog = ...
fromCatalog.Member = ...
readonly
readonly record struct