13

我们的商业模式中有一个学生课程。有件事让我觉得很奇怪,如果我们从另一个学生中操纵一个学生,学生的私人成员是可见的,这是为什么呢?

   class Program {
      static void Main(string[] args) {

         Student s1 = new Student();
         Student s2 = new Student();

         s1.SeePrivatePropertiesAndFields(s2);
      }
   }

   public class Student {

      private String _studentsPrivateField;

      public Student() {
         _studentsPrivateField = DateTime.Now.Ticks.ToString();
      }

      public void SeePrivatePropertiesAndFields(Student anotherStudent) {
         //this seems like these should be private, even from the same class as it is a different instantiation
         Console.WriteLine(anotherStudent._studentsPrivateField);
      }
   }

我可以对此的设计考虑/影响有一些想法吗?看来您无法向您的兄弟姐妹隐瞒信息。有没有办法将字段或成员标记为对同一类的其他实例隐藏?

4

11 回答 11

9

有一种简单的方法可以确保这一点:

不要与同一类的其他实例的私有成员混在一起。

说真的 - 你是编写Student代码的人。

于 2010-01-19T00:43:40.263 回答
8

确保这一点的最简单方法是对接口进行编程,例如:

class Program
{
    static void Main(string[] args)
    {
        IStudent s1 = new Student();
        IStudent s2 = new Student();

        s1.ExamineStudentsMembers(s1);
    }
}

public interface IStudent
{
    void ExamineStudentsMembers(IStudent anotherStudent);
}

public class Student : IStudent
{
    private string _studentsPrivateMember;

    public Student()
    {
        _studentsPrivateMember = DateTime.Now.Ticks.ToString();
    }

    public void ExamineStudentsMembers(IStudent anotherStudent)
    {
        Console.WriteLine(anotherStudent._studentsPrivateMember);
    }
}

由于 ExamineStudentsMembers 试图访问私有字段,这将不再编译。

于 2010-01-19T00:54:04.123 回答
6

如果您正在编写类,则可以完全控制它,因此如果您不希望一个对象能够修改另一个对象,请不要编写该功能。

类通常会在其他实例中使用私有变量来实现高效的比较和复制功能。

于 2010-01-19T00:49:46.333 回答
4
  • 私有只是意味着成员(字段/方法/等)只能从父类型的代码中访问。来自CSharpOnline
  • 多个实例的私有成员是可见的并且可以被调用。当您在类型上实现“复制构造函数”或“克隆”方法时,这会派上用场,其中参数是相同类型的实例。如果设计者将私有字段设为不可访问,那么您可能必须创建一堆 getter 方法,仅用于克隆/复制以获取它们。恕我直言,我更喜欢它的方式。在同一类型中,读取另一个对象的状态并不像写入它那么糟糕(这可能是您/您的团队的 DONT 代码约定。)
于 2010-01-19T01:03:37.550 回答
2

当措辞如下时,访问兄弟姐妹的私人数据可能看起来是错误的:

public void ExamineStudentsMembers(Student anotherStudent) {
    //this seems very wrong
    Console.WriteLine(anotherStudent._studentsPrivateMember);
}

但是,对于需要这种功能的方法来说,这似乎并不奇怪。哪些方法需要访问兄弟姐妹的私有数据?比较方法(特别是 equals)和数据结构中的对象(比如树或链表)。

比较方法通常直接比较私有数据而不仅仅是公共数据。

对于构成链表、图形或树的一类节点,能够访问兄弟节点的私有数据正是所需要的。已知代码(类的一部分)可以修改数据结构,但数据结构之外的代码不能触及内部。

有趣的是,这两种情况在日常编程中不如最初开发这种语言功能时常见。早在 1990 年代和 2000 年代初期,在 C++ 中构建自定义数据结构和比较方法会更为常见。也许现在是重新考虑私人会员的好时机。

于 2010-01-19T01:21:18.243 回答
2

我喜欢第二点,你可以看,但不要碰那些私人成员。

你应该这么说很有趣,我曾经认识一位老师,他说他经常在决定哪些班级可以查看成员以及他实际上可以玩哪些班级时遇到问题。

于 2010-01-19T11:51:47.027 回答
1

一个对象只是一段数据;该类包含功能。成员方法只是编译器玩的一个好把戏;它实际上更像是一个带有隐含参数的静态方法(有点像扩展方法)。考虑到这一点,相互保护对象没有任何意义。你只能互相保护类。因此,它以这种方式工作是很自然的。

于 2010-01-19T07:22:24.087 回答
0

不,这是必须的,方法代码不是特定于实例的,它只是特定于对象的类型。(虚拟方法)或变量的声明类型(对于非虚拟方法)。另一方面,非静态字段是特定于实例的......这就是您具有实例级隔离的地方。

静态方法和非静态方法之间的唯一区别是静态方法不允许访问其他基于实例(非静态)的方法或字段。任何可以在不修改的情况下变为静态的方法都不会受到静态的影响,除非强制编译器在使用基于实例的语法调用它的任何地方抛出错误。

于 2010-01-19T00:45:05.140 回答
0

如果您打算检查给定学生的信息,那么我会将方法更改为静态:

  public static void ExamineStudentsMembers(Student student)
  {
     Console.WriteLine(student._studentsPrivateMember);
  }

然后,您将使用Student.ExamineStudentsMembers(s1). 使用s1.ExamineStudentsMembers(s2)将是无效的。

如果这不是预期目的,我会将方法重写为:

  public void ExamineStudentsMembers()
  {
     Console.WriteLine(_studentsPrivateMember);
  }

然后将通过编写使用上述内容s1.ExamineStudentsMembers()

于 2010-01-19T00:48:41.517 回答
0

私人成员将对客户隐藏实施细节。客户端应该只看到接口(公共方法/字段/属性)。

目的不是保护程序员免受自己的伤害。

这也不是安全功能,因为您始终可以通过反射访问私有字段。

它实际上是分离接口和实现(黑盒设计),以及针对合同(所有公共领域)进行编程的客户端。

例如,如果您有一个公共 get 属性,它可以直接访问某个私有字段,或者它可以从其他一些字段计算值。目的是,客户端只知道合约(公共属性)并且可以在不影响客户端的情况下更改实现

于 2017-06-27T16:16:21.617 回答
-1

对象范围并不意味着安全——永远!操作系统的作用是提供运行时安全性。设计一个依赖于语言特定对象范围来限制运行时对象实例数据访问的系统是一个错误。如果不是这种情况,那么根据定义,所有非 OO 语言都是不安全的。

于 2010-01-19T12:54:19.923 回答