C# 为什么私有字段对类型而不是实例是私有的?

C# 为什么私有字段对类型而不是实例是私有的?,c#,oop,language-design,language-features,private-members,C#,Oop,Language Design,Language Features,Private Members,在C#(和许多其他语言)中,访问相同类型的其他实例的私有字段是完全合法的。例如: public class Foo { private bool aBool; public void DoBar(Foo anotherFoo) { if (anotherFoo.aBool) ... } } 正如(第3.5.1节、第3.5.2节)所述,对私有字段的访问是在类型上,而不是在实例上。我一直在和一位同事讨论这个问题,我们正试图找出这样做的原因(而不是限

在C#(和许多其他语言)中,访问相同类型的其他实例的私有字段是完全合法的。例如:

public class Foo
{
    private bool aBool;

    public void DoBar(Foo anotherFoo)
    {
        if (anotherFoo.aBool) ...
    }
}
正如(第3.5.1节、第3.5.2节)所述,对私有字段的访问是在类型上,而不是在实例上。我一直在和一位同事讨论这个问题,我们正试图找出这样做的原因(而不是限制对同一实例的访问)


我们可以提出的最佳论据是进行平等性检查,其中类可能希望访问私有字段以确定与另一个实例的平等性。还有其他原因吗?或者是某种黄金理由,绝对意味着它必须像这样工作,否则就完全不可能了?

这只是我的观点,但实际上,我认为如果程序员可以访问类的源代码,您可以合理地信任他们访问类实例的私有成员。既然你已经把王国的钥匙给了程序员,为什么还要把他们绑在左手上呢?

原因确实是平等性检查、比较、克隆、运算符重载。。。
例如,在复数上实现运算符+(operator+)是非常棘手的。

在我看来,如果数据对相同类型的其他实例是私有的,那么它就不一定是相同的类型了。它的行为或行为似乎与其他实例不同。基于该私有内部数据,可以很容易地修改行为。在我看来,这只会让混乱蔓延开来

粗略地说,我个人认为,编写从基类派生的类提供了与“每个实例都有私有数据”类似的功能。相反,您只需要为每个“unique”类型定义一个新的类。

因为在C#和类似语言中使用的封装类型的目的是降低不同代码段(C#和Java中的类)的相互依赖性,而不是内存中的不同对象

例如,如果您在一个类中编写的代码使用了另一个类中的某些字段,那么这些类是紧密耦合的。但是,如果您处理的代码中有两个相同类的对象,那么就没有额外的依赖关系。一个类总是依赖于它自己

然而,当有人创建属性(或Java中的get/set对)并直接公开所有字段时,所有关于封装的理论都失败了,这使得类就像访问字段一样耦合


*有关封装类型的说明,请参见Abel的优秀答案

这在许多语言中都是完全合法的(以C++为例)。访问修饰符来自OOP中的封装原则。其想法是限制对外部的访问,在这种情况下,外部是其他类。例如,C#中的任何嵌套类也可以访问其父级私有成员

而这是语言设计师的设计选择。这种访问限制会使一些非常常见的场景变得非常复杂,而不会对实体的隔离造成很大影响


有一个类似的讨论

我不认为我们有理由不增加另一个隐私级别,即每个实例的数据都是私有的。事实上,这甚至可能为语言提供一种良好的完整感

但在实际操作中,我怀疑它是否真的有用。正如您所指出的,我们通常使用的私有性,它对于等式检查以及涉及类型的多个实例的大多数其他操作都很有用。不过,我也喜欢你关于维护数据抽象的观点,因为这是OOP中的一个重要观点

我认为,以这种方式提供限制访问的能力是向OOP添加的一个很好的特性。真的那么有用吗?我会说不,因为类应该能够信任自己的代码。由于该类是唯一可以访问私有成员的对象,因此在处理另一个类的实例时,没有真正的理由需要进行数据抽象


当然,您总是可以编写代码,就像私有应用于实例一样。使用常用的
get/set
方法访问/更改数据。如果类可能会受到内部更改的影响,那么这可能会使代码更易于管理。

我认为它以这种方式工作的一个原因是访问修饰符在编译时工作。因此,确定给定对象是否也是当前对象并不容易。例如,考虑这个代码:

public class Foo
{
    private int bar;

    public void Baz(Foo other)
    {
        other.bar = 2;
    }

    public void Boo()
    {
        Baz(this);
    }
}
编译器是否能确定
其他
实际上就是
?并非所有情况下都如此。有人可能会说这不应该编译,但这意味着我们有一个代码路径,其中正确实例的私有实例成员无法访问,我认为这更糟糕

只需要类型级别而不是对象级别的可见性,就可以确保问题是可处理的,并且使问题看起来应该实际可行

编辑:丹尼勒·希尔加思(Danilel Hilgarth)认为这种推理是倒退的观点确实有价值。语言设计人员可以创建他们想要的语言,而编译器编写人员必须遵守它。话虽如此,语言设计者确实有一些动机让编译器编写人员更容易完成他们的工作。(尽管在这种情况下,很容易认为私有成员只能通过
this
(隐式或显式)访问)

然而,我认为这使这个问题变得更加混乱。如果上面的代码不起作用,大多数用户(包括我自己)都会发现这是不必要的限制:毕竟,这是我试图访问的数据!为什么我必须通过
这个

简言之,我认为我可能夸大了这一点,因为它对编译器来说是“困难的”。我真正想表达的是,上述情况似乎与设计无关
public class StringBuilder
{
    private string chunk;
    private StringBuilder nextChunk;
}
public override string ToString()
{
    return chunk + nextChunk.ToString();
}
public override string ToString()
{
    string ret = string.FastAllocateString(Length);
    StringBuilder next = this;

    unsafe
    {
        fixed (char *dest = ret)
            while (next != null)
            {
                fixed (char *src = next.chunk)
                    string.wstrcpy(dest, src, next.chunk.Length);
                next = next.nextChunk;
            }
    }
    return ret;
}
feature {classA, classB}
   methodName