2016-12-30 14 views
2

У меня возникли проблемы с пониманием того, как правильно инкапсулировать мой класс. Это (или должно быть).Как правильно скрыть помощники (внутренние) классы внутри класса в C#

Я использую «вспомогательный класс», и я хочу, чтобы он не был доступен снаружи.

namespace MyApp 
{ 

    [Flags] 
    public enum OctaveGroups 
    { 
     None = 0, 
     oneOctave = 1 
    } 

    class Frequencies 
    { 
     // HelperClass 
     public class Frequency 
     { 
      public string Name { get; set; } 
      public OctaveGroups Octave { get; set; } 
     } 

     public readonly static List<Frequency> All = new List<Frequency> 
     { 
     #region Complete Frequencies Data 

       new Frequency { Name = "63", Hz = 63, 
        Octave = OctaveGroups.oneOctave | OctaveGroups.None, 
        }, 

       new Frequency { Name = "80", Hz = 80, 
        Octave = OctaveGroups.None, 
        } 
      // And so on.. 
       //.. 

     #endregion 
     }; 


     public readonly List<Frequency> OneOctave = All.Where(f => f.Octave.HasFlag(OctaveGroups.oneOctave)).ToList(); 

     public readonly List<Frequency> None = All.Where(f => f.Octave.HasFlag(OctaveGroups.None)).ToList(); 

    } 
} 

Если бы я сделать мой Frequency класс protected или private я получаю эту ошибку:

Inconsistent accessibility: field type 'List' is less accesible than field 'Frequencies.All'

я получаю ту же ошибку, если я class Frequency и List<Frequency> All защищены и попытаться сделать метод, который возвращает List<Frequency> например:

public List<Frequency> GetAll() 
    { 
     return All.Where(f => f.Octave.HasFlag(OctaveGroups.OneOctave)).ToList(); 
    } 

Каким будет правильный способ разоблачения .All.OneOctave и .None поля, сохраняя их только для чтения?

+0

Если вы хотите, чтобы 'GetAll' был общедоступным,' Frequency' должен быть общедоступным. В чем вопрос? Что вы подразумеваете под «держать их только для чтения»?Метод, который возвращает материал, как это можно читать только, за исключением возвращения неизменных результатов? –

+3

Если вы подвергаете воздействию частоты, вы не можете сделать ее ни частной, ни защищенной, но если вам нужна неизменность, вы можете сделать внутренние сеттеры –

+0

Я потерял абзац в моей копии/вставке кода. Я хочу (если это возможно), чтобы мой помощник 'Class Frequency' не был доступен, потому что мне это не нужно в любом другом месте. – distante

ответ

6

Вы не можете ожидать, чтобы скрыть Frequency, когда вы планируете публичные методы возврата List<Frequency>.

Теперь я понимаю, что ваша проблема заключается в том, что вам нужны доступные средства определения свойств в Frequency от Frequencies, но вы не хотите выставлять их снаружи. Способ сделать это через интерфейс, который только выставляет добытчик:

public interface IFrequency 
{ 
    string Name { get; } 
    OctaveGroups Octave { get; } 
} 

И сейчас, вы делаете Frequencies.Frequency приватный вложенный класс и вы подвергаете только IFrequency:

class Frequencies 
{ 
    // HelperClass 
    private class Frequency: IFrequency 
    { 
     public string Name { get; set; } 
     public OctaveGroups Octave { get; set; } 
    } 

    public readonly static List<IFrequency> All = new List<IFrequency> 
    { 
    #region Complete Frequencies Data 

      new Frequency { Name = "63", Hz = 63, 
       Octave = OctaveGroups.oneOctave | OctaveGroups.None, 
       }, 

      new Frequency { Name = "80", Hz = 80, 
       Octave = OctaveGroups.None, 
       } 
     // And so on.. 
      //.. 

    #endregion 
    }; 


    public readonly List<IFrequency> OneOctave = All.Where(f => f.Octave.HasFlag(OctaveGroups.oneOctave)).ToList(); 

    public readonly List<IFrequency> None = All.Where(f => f.Octave.HasFlag(OctaveGroups.None)).ToList(); 

} 

Теперь потребитель Frequencies будет только см. IFrequency экземпляры, в которых нет сеттера, и поэтому он неизменен для внешнего мира (за исключением отражения, конечно).

2

Правильный способ не скрывать их.

Вы просто не можете и скрыть и выставить класс во внешний мир, в то же время.

Итак, если вы хотите объявить публичный метод, возвращающий объект или коллекцию объекта, вы должны также сделать тип рассматриваемого объекта общедоступным.

+0

Невозможно использовать внутренний класс только в своем родительском классе? – distante

+1

, конечно, есть, но не как возвращаемый тип публичного метода, как вы сделали –

+0

@OlegBogdanov мне нужно создать динамическое возвращение или подобное? Извините, что я пришел из мира Javascript, и мне сложно с этим (для меня) новыми типами. – distante

-1

Попробуйте добавить внутренний конструктор в свой частотный класс. Это позволит вам построить частоту изнутри класса, но не разрешать внешним классам создавать его. Поскольку он не может быть построен снаружи, никто из вне класса не сможет добавить новый в свои списки, так как они напечатаны на частоте.

Пример:

public class ExternalType 
    { 
     public class InternalType 
     { 
      internal InternalType(string someString) 
      { 
       SomeStringProp = someString; 
      } 

      public string SomeStringProp { get; private set; } 
     } 

     public readonly List<InternalType> InternalTypes = new List<InternalType>() 
     { 
      new InternalType("test") 
     }; 
    } 

Если вы пытаетесь создать экземпляр InternalType за пределами ExternalType вы получите ошибку компиляции. Однако ваши иждивенцы смогут прочитать список.

+0

У меня недостаточно репутации, чтобы добавить комментарии к ответам других людей, так что разместите это здесь. Если вы используете метод интерфейса, предложенный @InBetween, кто-то еще может наследовать интерфейс IFrequency и затем быть добавлен в списки на частоте. –

+0

Подумав об этом, метод @ InBetween будет работать, если вы сделаете публичные списки IEnumerable вместо списка , потому что IEnumerable не имеет метода добавления. –

+0

Вы можете создать экземпляр 'InternalType' вне' ExternalType' (в том же сборке, конечно). – apocalypse