2016-08-31 8 views
0

Рассмотрим C# программу:Как защищать нужно, когда возвращаете ссылку на объект, которая является просто частным членом, «запутанным» каким-то образом?

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace SandboxApplication 
{ 
    public class IntsOwner 
    { 
     private List<int> _ints; 

     public IntsOwner (IEnumerable<int> ints) 
     { 
      _ints = ints.OrderBy(i => i).ToList(); // They must be in the correct order 
     } 

     public IEnumerable<int> Ints 
      => _ints; 

     public void CheckFirstTwoInts() 
     { 
      if (_ints.Count < 2) 
      { 
       Console.WriteLine("You need to collect some more ints before trying this."); 
      } 
      else if (_ints[0] <= _ints[1]) 
      { 
       Console.WriteLine("Your ints are in the correct order and you should stop worrying."); 
      } 
      else 
      { 
       Console.WriteLine("You've failed, your highness."); 
      } 
     } 
    } 

    class Program 
    { 
     static void Main (string[] args) 
     { 
      var intsOwner = new IntsOwner(new List<int> {1, 2, 3, 4, 5}); 

      var ienumerable = intsOwner.Ints; 

      var list = (List<int>)ienumerable; 

      intsOwner.CheckFirstTwoInts(); 

      list[0] = 6; 

      intsOwner.CheckFirstTwoInts(); 

      Console.ReadLine(); 
     } 
    } 
} 

Если запустить это, вы получите две строки вывода:

Your ints are in the correct order and you should stop worrying. 
You've failed, your highness. 

оригинальный конструктор IntsOwner класса хотел, чтобы убедиться, что конкретное имущество (порядок элементов списка) для частного участника _ints. Но поскольку ссылка на фактический объект возвращается через свойство Ints, пользователь класса может изменить объект, чтобы это свойство больше не выполнялось.

Этот тип кода на практике не кажется очень вероятным, но он все еще сбивает с толку, что контроль членов, предназначенных для частных, может «протекать» таким образом. Сколько, если вообще, должны ли программисты попытаться заблокировать подобные вещи? Например, было бы разумным или пропорциональным изменить тело выражения объекта Ints на _ints.Select(i = i) и тем самым закрыть этот способ изменения частного члена? Или это будет излишне параноидально в ущерб читаемости кода?

+0

Причина, по которой '_ints' может быть изменен даже если он является частным, потому что _reference_ к нему передается при вызове public property get. Чтобы защитить частный список, решение, похоже, должно было бы вернуть копию этого свойства через свойство, но как можно было бы управлять действительными изменениями? Нелегкая (или даже необходимая) проблема для решения. –

+1

Думаю, я бы не стал беспокоиться об этом. Приведение в «Список» явного использования «внутренней» информации - это на один шаг от простого захвата частного члена посредством отражения. Вы явно просматриваете только информацию, доступную только для чтения, через открытый интерфейс класса. – Blorgbeard

+0

Кстати, с отражением в .Net мы можем получить доступ ко всем членам, методам, свойствам и т. Д., Независимо от их «частной» области, что в любом случае делает такие соображения устаревшими. –

ответ

-3

Вы могли бы сделать что-то вроде

public IEnumerable<int> Ints => _ints.ToList<int>(); 

так что вы не возвращает ссылку на _ints, но только скопированный список. Любой, кто модифицирует возвращаемое значение, будет изменять только свою собственную копию, а не частную.

+0

OP знает это, он упоминает аналогичное решение '_ints.Select (i = i)'. Он спрашивает, нужна ли это/хорошая идея. – Blorgbeard