我们经常被告知我们应该通过为类字段制作getter和setter方法(C#中的属性)来保护封装,而不是将字段暴露给外部世界.
但是很多时候,一个字段只是用来保存一个值,并且不需要任何计算来获取或设置.对于这些,我们都会这样做:
public class Book
{
private string _title;
public string Title
{
get{ return _title; }
set{ _title = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,我有一个坦白,我不忍心写所有这些(真的,它不必写它,它不得不看它),所以我去流氓和使用公共领域.
然后是C#3.0,我看到他们添加了自动属性:
public class Book
{
public string Title {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
这更整洁,我很感激它,但是真的,除了创建一个公共领域之外还有什么不同?
public class Book
{
public string Title;
}
Run Code Online (Sandbox Code Playgroud) 我意识到它似乎是C#中字段和属性之间有什么区别的重复?但我的问题略有不同(从我的观点来看):
一旦我知道了
是否有任何区别(风格/未来发展除外),如设置属性时的某种控制类型?
是否有任何额外的区别:
public string MyString { get; set; }
Run Code Online (Sandbox Code Playgroud)
和
public string myString;
Run Code Online (Sandbox Code Playgroud)
(我知道,第一个版本需要C#3.0或更高版本,并且编译器会创建私有字段.)
例如,在Java中,我可以自己编写getter(由IDE生成)或者在lombok中使用@Getter之类的注释 - 这非常简单.
然而,Kotlin 默认拥有getter和setter.但我无法理解如何使用它们.
我想说,就像Java一样:
private val isEmpty: String
get() = this.toString() //making this thing public rises an error: Getter visibility must be the same as property visibility.
Run Code Online (Sandbox Code Playgroud)
那么吸气剂如何工作?
我对C#中的自动属性有点困惑,例如
public string Forename{ get; set; }
Run Code Online (Sandbox Code Playgroud)
我知道你不需要声明私有变量来保存代码,但是当你不使用任何get或set逻辑时,属性的重点是什么?为什么不用
public string Forename;
Run Code Online (Sandbox Code Playgroud)
我不确定这两个语句之间有什么区别,如果你想要额外的get/set逻辑,我一直认为你使用过属性?
在以前版本的Visual Studio中,我可以在C#中创建一个单行自动启动器,如下所示:
public int Whatever { get; set; }
Run Code Online (Sandbox Code Playgroud)
如果我按Control-K,Control-D格式化,属性将保持这种状态.
但是在Visual Studio 2015 RC中,当我键入属性时,它会换行,即使我打开它,格式化再次包装它:
public int Whatever
{ get; set; }
Run Code Online (Sandbox Code Playgroud)
我也注意到了构造函数.在过去,一个空的构造函数(例如,刚刚调用的基类构造函数)可能如下所示:
public Whatever(int stuff)
: base(stuff) { }
Run Code Online (Sandbox Code Playgroud)
现在,Visual Studio 2015坚持这样做:
public Whatever(int stuff)
: base(stuff)
{ }
Run Code Online (Sandbox Code Playgroud)
有人注意到了吗?这是Visual Studio 2015中的更改吗?如果是这样,有没有办法可以改回来?我查看了工具>选项的C#格式化部分,但找不到任何可能影响此设置的新设置.
(我的加载项之一导致它并非不可能,但我没有发现任何明显的罪魁祸首.)
(为什么要关心?因为当我使用Collapse to Definitions概述命令时,单行属性和构造函数保持原样,而包裹的属性会崩溃.如果它们崩溃了,我无法一眼就看出它们是空的;我必须将它们切换到未收缩状态,只是为了看到那里什么都没有.)
我对C#很新,我认为属性是一件很棒的事情.事实上,如此精彩,我看不到使用字段的任何真正优势.即使对于私人领域,性能提供的灵活性和模块性似乎最多可以避免严重的麻烦,最糟糕的是根本没有效果.
我可以在字段中看到的唯一优势是您可以内联初始化它们.但是大多数时候,你想在构造函数中初始化它们.如果您不使用内联初始化,是否有任何理由不使用属性?
编辑:有些人提出需要使用字段备份属性(显式或自动).让我们澄清一下我的问题:除了备份属性之外,有没有理由使用字段?也就是说,有没有比这SomeType someField;
更好的时间了SomeType SomeProperty { get; set; }
?
编辑2:DanM,Skurmedel和Seth都提供了非常有用的答案.我已经接受了DanM,因为它是最完整的,但如果有人将他们的回答总结为一个答案,我会很乐意接受它.
首先,我已经阅读了关于这个主题的帖子列表,并且由于我对封装和字段修饰符(private,public..ect)的了解,我不觉得我已经掌握了属性.
我学习的C#的一个主要方面是使用封装在代码中保护数据的重要性.我认为'我理解这是因为使用修饰符的能力(私人,公共,内部,受保护).然而,在了解了属性之后,我不仅理解了属性的使用,而且还理解了C#中数据保护(我理解为封装)的整体重要性/能力.
更具体地说,当我到达C#中的属性时,我读过的所有内容都是你应该尝试使用它们代替字段,因为:
1)当您直接直接访问字段时,它们允许您更改数据类型.
2)它们为数据访问增加了一定程度的保护
然而,根据我的想法,我已经了解了字段修饰符的使用#2,在我看来属性只是生成了额外的代码,除非你有一些理由改变类型(#1) - 因为你是(或多或少)创建隐藏方法来访问字段而不是直接访问.
然后可以将整个修饰符添加到属性中,这进一步使我对属性访问数据的需要的理解变得复杂.
我已经阅读了不同作者关于"属性"的一些章节,并且没有人真正解释过对属性与字段与封装(以及良好的编程方法)的良好理解.
有人能解释一下:
1)为什么我想要使用属性而不是字段(特别是当它出现时我只是添加额外的代码
2)在跟踪其他人的代码时,有关识别属性的使用以及不将它们视为简单方法(除了get; set明显)之外的任何提示吗?
3)任何关于何时使用什么的良好编程方法的一般经验法则?
感谢和抱歉这篇长篇文章 - 我不想只问一个问题100x而不解释为什么我再问它.
我正在使用JavaScriptSerializer来序列化一些实体对象.
问题是,许多公共属性包含null或默认值.有没有办法让JavaScriptSerializer排除属性为null或默认值?
我希望生成的JSON不那么冗长.
人们似乎教条地坚持在田野上使用公共财产,但为什么在简单财产的情况下它如此重要?
怎么
public int Foo { get; set; }
Run Code Online (Sandbox Code Playgroud)
非常不同于
public int Foo;
Run Code Online (Sandbox Code Playgroud)
?
在我的脑海中,我可以想到两者之间的实际差异:
除了这些非常罕见的情况之外,稍后将Foo更改为计算属性会导致更改0行代码.
当我写一个类时,我总是通过这样的公共属性公开私有字段:
private int _MyField;
public int MyField
{ get{return _MyField; }
Run Code Online (Sandbox Code Playgroud)
什么时候可以公开这样的公共字段:
public int MyField;
Run Code Online (Sandbox Code Playgroud)
我正在创建一个名为Result的结构,我的意图是这样做:
public Result(bool result, string message)
{
Result = result;
Message = message;
}
public readonly int Result;
public readonly int Message;
Run Code Online (Sandbox Code Playgroud)
什么是最佳做法?这样做好吗?