我理解提供一个间接访问类成员的接口的好处.我的问题是:并不是你已经可以用任何OO语言完成的东西(有些东西)
public int NormalClass::getQuality() {
    return this->quality;
}
和
protected void NormalClass::setQuality(int q) {
    this->quality = q;
}
?
除了纯粹的美学外,.NET属性还提供了哪些额外的好处?
如果你能为它做出令人信服的论证,我会接受"可读性"; 但就个人而言,我倾向于认为get/set函数比属性更具可读性,因为它明确地是一个函数而不是一个直接值.
编辑:感谢大家的回答!这对我来说真的很有用; 总结一下我从所有人那里收集/学到的东西,以下是我到目前为止得出的一些结论:
现在,到目前为止,有两点已经在2或3个答案中做出,我个人觉得有点可疑:这些属性意味着廉价的读/写操作,因此可以与简单变量基本相同的方式使用.我关于这一点的问题是,实际上强制执行此操作的属性中没有固有的东西; 这只是他们如何应该使用.对我来说,这是类似于一个"shouldBePrivate"限定符指示值应该只由它自己的类直接访问,但仍然可以从外部访问无论如何; 还是在街上巡逻的警察部队提醒我们,我们应该表现自己,但在我们开始犯罪时实际上并没有干涉(如果没有强制执行,它对我们真正做了什么?).
如果属性具有某种内置机制来确保读/写便宜,我会对这一点印象更深刻.
编辑2009年11月4日
好的,自从我第一次发布这个问题以来已经有一段时间了.在我看来,许多最初的响应者都没能真正得到我所说的 - 一个共同的反应是"你所说的没有任何意义"的一些变化 - 所以我做了一些方便图表真的说明了我的观点.
当我们谈到数字时,我们通常指的是学校儿童学习的等级被称为数字线:

现在,当我们学习算术时,我们的思想学会对这个概念进行非常有趣的转换.1 + 0.5例如,如果我们只是应用我们的"数字线思维",那么评估表达式将要求我们以某种方式理解这一点:

很难真正说明这一点,因为很难想到这一点:"增加"两点.这是许多响应者在添加日期(或者简单地认为它是荒谬的)的想法中挣扎的地方,因为他们认为日期是积分.
然而,这个表达1 + 0.5 确实对我们有意义,因为当我们想到它时,我们真的想象这个:

也就是说,数字(或点)1加上矢量 0.5,得到点 1.5.
或者,我们可能想象这个:

也就是说,向量 1加上向量 0.5,得到向量 1.5.
换句话说,在处理数字时,我们可以互换地处理点和向量.但是约会怎么样?毕竟,日期基本上是数字.如果您不相信我,请将此行与上面的数字行进行比较:

注意时间线和数字线之间的对应关系?这就是我的观点:如果我们用数字执行上面的转换,我们也应该能够用日期来完成.所以,应用"时间轴思维",这个表达0001-Jan-02 00:00:00 + 0001-Jan-01 12:00:00并没有多大意义,因为很多响应者指出:

但是,如果我们在每次添加或减去数字时执行相同的概念转换,我们可以轻松地"重新考虑"上述内容:

很明显,a DateTime和a 之间的TimeSpan差异与点和矢量之间存在的差异相同.我认为让很多人对我的建议做出负面反应的是,以这种方式将日期视为大小只是感觉如此不自然.但我不认为没有明显的参考点可以用作零.有一个明显的参考点,我会给你一个暗示:大约在2010年前.
不要误解我的意思:我不是在质疑a 和a 的概念之间划分概念的有用性.说真的,我的问题一直以来应该是(为ChrisW间接暗示),为什么做我们对待数字和载体互换与普通数字类型打交道?(或者:为什么我们只有一种类型,而不是和?)有一个很大的区别,但是在初中或高中,当我们开始几何时,我们从来没有真正考虑过它.然后它被视为这个新的数学概念,而实际上它是我们一直在利用的东西,因为我们通过用手指计数来学习添加数字.DateTimeTimeSpanintintintspan
最后,最好的答案来自Strilanc,他指出使用DateTime和TimeSpan实际上是仿射空间的实现,它具有不需要参考点作为原点的方便性.谢谢,Strilanc.然而,我给出了ChrisW的接受答案,因为他是第一个提出矢量和点的概念的人,这真正解决了问题的关键.
原始问题(后代)
我当然不是所有行业的编程插孔,但我知道PHP和.NET …
首先,只是授予我实际上想要的功能Queue<T>-  FIFO,通常只需要Enqueue/ Dequeue等等 - 所以我更喜欢"你真正想要的是什么"之外的答案List<T>(我知道)关于RemoveAt).
例如,假设我有一个Queue<DataPoint> dataToProcess数据点需要按照它们到达的顺序进行处理.然后定期有一些像这样的代码是有意义的:
while (dataToProcess.Count > 0) {
    DataPoint pointToProcess = dataToProcess.Dequeue();
    ProcessDataPoint(pointToProcess);
}
但是,无论出于何种原因,我们都会发现,不应该处理已添加到队列中的特定数据点.那么如果有一种类似于以下的方法,那将是理想的:
dataToProcess.Remove(badPoint);
我明白,实际上没有可行的方法来获得一种Remove不涉及某种形式的枚举的方法; 但是,因为a Queue<T>并不是真的让你随便走进并随机删除一些项目,我能想出的唯一解决方案是:
bool Remove(T item) {
    bool itemFound = false;
    // set up a temporary queue to take items out
    // one by one
    Queue<T> receivingQueue = new Queue<T>();
    // move all non-matching items out into the
    // temporary queue
    while (this.Count > …好的,经过一番调查,并且在很大程度上要归功于Jon和Hans提供的有用答案,这就是我能够把它放在一起的.到目前为止,我认为它似乎运作良好.当然,我不打赌我的生活完全正确.
public static int GetSignificantDigitCount(this decimal value)
{
    /* So, the decimal type is basically represented as a fraction of two
     * integers: a numerator that can be anything, and a denominator that is 
     * some power of 10.
     * 
     * For example, the following numbers are represented by
     * the corresponding fractions:
     * 
     * VALUE    NUMERATOR   DENOMINATOR
     * 1        1           1
     * 1.0      10          10
     * 1.012    1012        1000
     * 0.04     4           100
     * 12.01    1201        100
     * …我正在开发一个JavaScript项目,涉及在键盘仿真模式下从USB磁条阅读器读取信用卡和驾驶执照.事实证明,获得信用卡非常容易,因为它们都是相同的格式.然而很快就发现驱动程序的许可证更加困难,因为即使在单个状态(CA)内,格式也会因卡片而异.
在任何情况下,目标都是从原始数据中取出驾驶执照(使用磁条阅读器)并从中提取数字,从而为尽可能多的美国州产生正确的数字(所有50个将太棒了).值得一提的是,我并不特别关注验证,至少在这一点上并非如此.
有没有其他人已经这样做了,并将它打包在一个我可以使用的库(免费或商业)中?那将是真棒.
我还应该注意,虽然我很想看到一个JavaScript解决方案,但实际上我愿意调查用任何语言编写的任何解决方案.
信不信由你,我继续把这个界面整合到我开始的开源库中,Tao.NET.我写了一篇博客文章解释这个库的IArray<T>界面,它不仅解决了我最初在这个问题中提出的问题(一年前?!),而且还提供了协变索引界面,这在BCL中非常缺乏(在我看来).
我问为什么.NET有IList<T>,它实现ICollection<T>,因此提供的方法来修改列表(Add,Remove,等),但不提供任何在两者之间的接口,如IArray<T>提供通过索引没有任何列表修改随机访问.
在以乔恩斯基特原来的答案评论(其中他质疑多久人们就必须需要任何合同,如IArray<T>),我提到Keys和Values该属性SortedList<TKey, TValues>类是IList<TKey>与IList<Value>分别,到乔恩回答说:
但在这种情况下,它被声明为IList,你知道只使用索引器....它并不是非常优雅,我同意 - 但它实际上并没有给我带来任何痛苦.
这是合理的,但我会回答说它不会给你带来任何痛苦,因为你只知道你做不到.但你知道的原因并不是从代码中清楚地看出来; 这是你有经验的SortedList<TKey, TValue>课程.
如果我这样做,Visual Studio不会给我任何警告:
SortedList<string, int> mySortedList = new SortedList<string, int>();
// ...
IList<string> keys = mySortedList.Keys;
keys.Add("newkey");
据说这是合法的IList<string>.但我们都知道,它会导致异常.
纪尧姆也提出了一个恰当的观点:
好吧,接口并不完美,但开发人员可以在调用Add/Remove/Set之前检查IsReadOnly属性...
再次,这是合理的,但是:这不会让你觉得有点迂回吗?
假设我定义了一个接口如下:
public interface ICanWalkAndRun …更新2:对于子孙后代,我就这样做了(感谢Jorg的输入):
100.step(2, -2) do |x|
    # my code
end
(显然有很多方法可以做到这一点;但听起来这是最"Ruby"的方式;而这正是我所追求的.)
更新:好的,所以我要找的是step:
(2..100).step(2) do |x|
    # my code
end
但事实证明,在我原来的问题中,我并非100%即将到来.我实际上想要向后迭代这个范围.令我惊讶的是,消极的一步是不合法的.
(100..2).step(-2) do |x|
    # ArgumentError: step can't be negative
end
那么:我该怎么做呢?
嘿伙计们,我对Ruby 很新,所以要温柔.
假设我想迭代从2到100的偶数范围; 我该怎么办?
显然我可以这样做:
(2..100).each do |x|
    if x % 2 == 0
        # my code
    end
end
但是,显然(再次),这将是非常愚蠢的.
我知道我可以这样做:
i = 2
while i <= 100
    # my code
    i += 2
end
我相信我也可以编写自己的自定义类,提供自己的each方法(?).不过,我几乎可以肯定这会有点矫枉过正.
我对两件事感兴趣: …
更新:我在Eric Lippert对另一个问题的回答中偶然发现了这个问题(他引用了这个规范):
其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是原子的.
好了,阅读double是不是原子.这意味着可以在读取中间修改该值,对吧?那么如何以double原子方式读取值?
我注意到有一种价值Interlocked.Read方法long.这对我来说很有意义,因为读取64位值必须需要两个步骤,因此就像其他所有非原子动作一样受到竞争条件的影响.
但目前还没有Interlocked.Read对double价值观,即使System.Double是一个64位的值.
我在我的程序中看到一些奇怪的行为,我的GUI double在文本框中显示,而double其他线程也经常更新,在大多数时间显示正确的值(在200.0附近),然后偶尔随机显示错误值(如-0.08).
也许这是一个线程问题,或者也许是其他问题.但首先我想缩小可能性.那么:正在阅读double线程安全吗?
之前,我甚至问,让我得到了明显的答案的方式进行:该ICollection<T>接口包括Remove删除任意元素,该方法Queue<T>并Stack<T>不能真正支持(因为他们只能删除"结束"元素).
好的,我意识到了.实际上,我的问题并不是关于Queue<T>或Stack<T>收集类型; 更确切地说,它是关于不执行的设计决定ICollection<T>了任何泛型类型是基本的集合T值.
这是我觉得奇怪的事情.假设我有一个接受任意集合的方法T,并且出于我正在编写的代码的目的,知道集合的大小会很有用.例如(以下代码是微不足道的,仅供参考!):
// Argument validation omitted for brevity.
static IEnumerable<T> FirstHalf<T>(this ICollection<T> source)
{
    int i = 0;
    foreach (T item in source)
    {
        yield return item;
        if ((++i) >= (source.Count / 2))
        {
            break;
        }
    }
}
现在,除了那些类型没有实现之外,没有理由为什么这个代码不能在a Queue<T>或a 上运行.当然,他们确实实现了 - 我主要是为了单独测试属性 - 但是这会导致像这样的奇怪的优化代码:Stack<T>ICollection<T>ICollectionCount
// OK, so to accommodate …字符串是引用类型,但它们是不可变的.这允许它们被编译器实现; 在出现相同的字符串文字的地方,可以引用相同的对象.
委托也是不可变的引用类型.(使用+=运算符向多播委托添加方法构成赋值 ;这不是可变性.)而且,就像字符串一样,有一种"文字"方式来表示代码中的委托,使用lambda表达式,例如:
Func<int> func = () => 5;
该语句的右侧是一个类型为的表达式Func<int>; 但我没有明确地调用Func<int>构造函数(也没有发生隐式转换).所以我认为这基本上是一个文字.我在这里误解了我对"文字"的定义吗?
无论如何,这是我的问题.如果我有两个变量,比如Func<int>类型,我将两个相同的lambda表达式分配给:
Func<int> x = () => 5;
Func<int> y = () => 5;
...什么阻止编译器将这些视为同一个Func<int>对象?
我问,因为C#4.0语言规范的第6.5.1节明确指出:
将具有相同(可能为空)的捕获的外部变量实例集的语义相同的匿名函数转换为相同的委托类型是允许(但不是必需的)返回相同的委托实例.这里使用术语相同的术语来表示在所有情况下,在给定相同参数的情况下,匿名函数的执行将产生相同的效果.
当我读到它时,这让我感到惊讶; 如果明确允许这种行为,我希望它能够被实现.但似乎并非如此.事实上,这已经让很多开发人员陷入困境,尤其是 当lambda表达式用于成功附加事件处理程序而不能删除它们时.例如:
class EventSender
{
    public event EventHandler Event;
    public void Send()
    {
        EventHandler handler = this.Event;
        if (handler != null) { handler(this, EventArgs.Empty); }
    }
}
class Program
{
    static string ….net ×7
c# ×2
interface ×2
queue ×2
cardreader ×1
collections ×1
datetime ×1
decimal ×1
delegates ×1
double ×1
expression ×1
hid ×1
icollection ×1
ilist ×1
javascript ×1
lambda ×1
oop ×1
precision ×1
properties ×1
range ×1
readonly ×1
ruby ×1
stack ×1
timespan ×1