解释 public 变量; (vs) public 变量 {get;设置;} C# 的区别?
explain public variable ; (vs) public variable {get; set;} difference in C#?
类似的问题已经问了很多,但对我这个初学者来说仍然没有意义。
这里是 link
What is the { get; set; } syntax in C#?
如该回答所述
(为了避免混淆,我将使用年龄而不是“姓名”)
案例一
public class Genre
{
public int Age { get; set; }
}
和
案例二:
public class Genre
{
private int age;
public int Age
{
get
{
return this.age;
}
set
{
this.age = value;
}
}
}
两者是一回事
那么对于案例 1,私有年龄变量在哪里?
是否在后端声明。
如果是,那么将为其分配什么名称?
肯定不是(年龄 => 年龄)对吧?
感觉就像,
public int Age { get; set; }
// is same thing as
public int Age;
现在,人们提到一个是 属性 另一个是字段。但是它们都可以以类似的方式使用。那么在应用层面有什么不同呢?
能举个例子吗?
将它们用作简单变量没有区别,但将变量用作 属性 使您能够执行检查或创建事件处理程序。例如:
private int _onetoten;
public int OneToTen
{
get => _onetoten;
set
{
if ((value > 0) && (value < 11))
{
_onetoten = value;
}
}
}
It feels like,
public int Age { get; set; }
is same thing as
public int Age;
绝对不是,第一个是两个函数,setter和getter,而第二个是一个字段,一个整数。作为差异的物理示例,您可以在第二个示例中执行 ref Age
,因为它在内存中有一个物理位置,但在第一个示例中不是,因为它只是函数,它是代码。
So for Case 1, where is private age variable? Does it get declared in the backend. If Yes, then what name will be assign to it?
是的,编译器为您生成了一个您不能在 C# 中声明的名称,因为它包含无效字符(通常在 .Net 中有效)。实际名称无关紧要,只知道你不可能使用它或与它发生碰撞。
你最后一个代码片段中两个成员的主要区别是封装
参见本页的“封装”部分:
https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop
Hiding the internal state and functionality of an object and only allowing access through a public set of functions.
您询问如果使用自动 属性 会生成什么私有字段。事实上,编译器会生成一个私有的支持字段,通常称为 k__BackingField 或类似的东西。
比如我创建了一个基本的class如下:
public class Dog
{
public string Name { get; set; }
}
这肯定是在后台创建了一个字段,我用ILSpy反编译就知道了,我们看到如下:
请注意名称 属性 与您预期的一样,其中包含 getter 和 setter。但还要注意 k__BackingField.
当我们检查它时,它由以下代码组成:
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string <Name>k__BackingField;
所以我们可以看到后台肯定有一个私有字段正在为属性生成。我们还可以通过检查名称 属性:
上的 get_Name getter 来确认它确实使用了该字段
[CompilerGenerated]
{
return <Name>k__BackingField;
}
Name getter 属性 确实 returns 编译器为我们生成的私有字段。
我认为您的疑惑是为什么我们会这样做。基本上,如果你只是在 class 上有一个 public 字段,你就允许 all-and-any 其他 classes 设置和获取该字段而无需任何类型的检查或关于设置或检索该值时发生的事情的平衡或规则。对于不是很复杂的小型应用程序,这不会给您带来问题。但将来当您编写更大的应用程序或库时,当您想要保证 某些功能始终以相同的方式运行时,这种最佳实践将是必要的。
类似的问题已经问了很多,但对我这个初学者来说仍然没有意义。
这里是 link
What is the { get; set; } syntax in C#?
如该回答所述 (为了避免混淆,我将使用年龄而不是“姓名”)
案例一
public class Genre
{
public int Age { get; set; }
}
和
案例二:
public class Genre
{
private int age;
public int Age
{
get
{
return this.age;
}
set
{
this.age = value;
}
}
}
两者是一回事
那么对于案例 1,私有年龄变量在哪里?
是否在后端声明。
如果是,那么将为其分配什么名称?
肯定不是(年龄 => 年龄)对吧?
感觉就像,
public int Age { get; set; }
// is same thing as
public int Age;
现在,人们提到一个是 属性 另一个是字段。但是它们都可以以类似的方式使用。那么在应用层面有什么不同呢?
能举个例子吗?
将它们用作简单变量没有区别,但将变量用作 属性 使您能够执行检查或创建事件处理程序。例如:
private int _onetoten;
public int OneToTen
{
get => _onetoten;
set
{
if ((value > 0) && (value < 11))
{
_onetoten = value;
}
}
}
It feels like,
public int Age { get; set; }
is same thing as
public int Age;
绝对不是,第一个是两个函数,setter和getter,而第二个是一个字段,一个整数。作为差异的物理示例,您可以在第二个示例中执行 ref Age
,因为它在内存中有一个物理位置,但在第一个示例中不是,因为它只是函数,它是代码。
So for Case 1, where is private age variable? Does it get declared in the backend. If Yes, then what name will be assign to it?
是的,编译器为您生成了一个您不能在 C# 中声明的名称,因为它包含无效字符(通常在 .Net 中有效)。实际名称无关紧要,只知道你不可能使用它或与它发生碰撞。
你最后一个代码片段中两个成员的主要区别是封装
参见本页的“封装”部分: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop
Hiding the internal state and functionality of an object and only allowing access through a public set of functions.
您询问如果使用自动 属性 会生成什么私有字段。事实上,编译器会生成一个私有的支持字段,通常称为 k__BackingField 或类似的东西。
比如我创建了一个基本的class如下:
public class Dog
{
public string Name { get; set; }
}
这肯定是在后台创建了一个字段,我用ILSpy反编译就知道了,我们看到如下:
请注意名称 属性 与您预期的一样,其中包含 getter 和 setter。但还要注意 k__BackingField.
当我们检查它时,它由以下代码组成:
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string <Name>k__BackingField;
所以我们可以看到后台肯定有一个私有字段正在为属性生成。我们还可以通过检查名称 属性:
上的 get_Name getter 来确认它确实使用了该字段[CompilerGenerated]
{
return <Name>k__BackingField;
}
Name getter 属性 确实 returns 编译器为我们生成的私有字段。
我认为您的疑惑是为什么我们会这样做。基本上,如果你只是在 class 上有一个 public 字段,你就允许 all-and-any 其他 classes 设置和获取该字段而无需任何类型的检查或关于设置或检索该值时发生的事情的平衡或规则。对于不是很复杂的小型应用程序,这不会给您带来问题。但将来当您编写更大的应用程序或库时,当您想要保证 某些功能始终以相同的方式运行时,这种最佳实践将是必要的。