2014-09-18 10 views
5

Wyobraź sobie, że masz zdefiniowaną klasę.C# References; Utrzymywanie członków w ukryciu

public class SomeClass 
{ 
    public Manager m { get; protected set; } 
    public SpecialData data { get; protected set; } 

    //More methods and member code here... 
} 

Potrzebuję mojej klasy menedżera, aby jakoś zmienić zestaw odniesienia dla członka SpecialData. Mógłbym to zrobić z podwójnym wskaźnikiem lub klasami znajomych w C++, ale ta opcja nie jest dostępna w C#, niestety. W jaki sposób mogę zabezpieczyć SpecialData przed zewnętrznymi użytkownikami, pozostawiając kontrolę klasy nad ustawieniami? Mogę to zrobić za pomocą wewnętrznego słowa kluczowego, ale to nie wydaje się niewiarygodnie bezpieczne ani czyste ...

Każda pomoc jest bardzo doceniana.

+2

Czy możesz wyjaśnić, dlaczego uważasz, że "wewnętrzne" jest niebezpieczne lub nieczyste? Czy masz na myśli, że jest tak ogólnie, czy sugerujesz, że nie pasuje do twojego konkretnego projektu? Powiedziałbym, że jest to idealne rozwiązanie, choć prawdę mówiąc, nie jestem pewien, dlaczego chcesz to zrobić w pierwszej kolejności. – decPL

Odpowiedz

4

Jeśli klasa menedżer jest częścią tego samego zespołu co SomeClass, dzięki czemu element internal pozwoliłoby na zajęcia w tym samym zespole, aby uzyskać dostęp do setter:

public SpecialData data { get; protected internal set; } 

ten jest podobny do korzystania friend w C++, z wyjątkiem tego, że "przyjaźń" jest rozszerzona na wszystkich członków tego samego zespołu.

Jeśli menedżer jest częścią innego pakietu, można użyć atrybutu InternalsVisibleTo w zespole. W tym przypadku jednak powinieneś podpisać zespół, do którego rozszerzysz przyjaźń, aby uniknąć prób uzyskania dostępu do setera z nieautoryzowanego kodu.

+0

Wspomniałem wewnętrzne słowo kluczowe. Rozumiem, że to opcja, ale czy to jest dobre? Martwiłem się, że ktoś może być wadą projektu. Jeśli nie, to na pewno zadziała. To duży projekt, więc łączenie ich razem może być ogromnym problemem ... – guitar80

+0

@ user3812869 Tak, 'internal' jest dobrym rozwiązaniem. Jest przeznaczony do takich sytuacji, gdy projektujesz pakiet powiązanych klas, które dzielą się wiedzą o wewnętrznej reprezentacji. .NET podejmuje środki ostrożności, aby nie ujawnić tej wiedzy poza biblioteką. Przypuszczalnie nie ma sposobu, aby chronić swój kod przed osobami, które mogą modyfikować twoje zgromadzenie. – dasblinkenlight

+0

Cóż, w takim razie spróbuję rozwiązać problem. Projekt wydaje mi się nieco dziwny. W rzeczywistości mam StateManager i Sprite zawarte w obiekcie gry. StateManager zawiera stany. Te państwa muszą edytować pole Sprite. – guitar80

1

utworzyć klasę, która dziedziczy SomeClass i wygląda rodzaju to:

internal class SomeClassDecorator : SomeClass 
{ 
    public void SetSpecialData(SpecialData value) 
    { 
     data = value; 
    } 
} 

Protected oznacza, że ​​jest ona dostępna do pochodnych klasy, a ponieważ SomeClass nie jest uszczelniona, można po prostu czerpać z niego i czynić czegokolwiek potrzebujesz. Możesz wtedy użyć tego dekoratora zamiast samego SomeClass. Co więcej, możesz mieć tyle dekoratorów, ile potrzebujesz, z których każdy obsługuje specjalne urządzenie SpecialData.

1

Może to nie być dokładnie to, czego szukasz, ale słowo kluczowe internal opisane here może zarządzać dostępem w obrębie tego samego zespołu; wydaje się być podobnym celem, jak słowo kluczowe friend w C++.

1

Można wprowadzić właściwość internal. To sprawi, że właściwość będzie widoczna tylko w tym samym zespole. Opcjonalnie można użyć opcji InternalsVisibleToAttribute, aby umożliwić określonym zestwom dostęp do tej właściwości.

Innym podejściem jest użycie interface ukryć, że właściwość:

public interface ISomeClass 
{ 
    Manager m { get; } 
    SpecialData data { get; set; } 
} 

public class SomeClass : ISomeClass 
{ 
    public Manager m { get; protected set; } 
    SpecialData ISomeClass.data { get; set; } 

    //More methods and member code here... 
} 

W ten sposób data jest widoczne z Interface.

Więc to nie działa:

SomeClass c = new SomeClass(); 
c.data; 

Ale to robi:

ISomeClass c = new SomeClass(); 
c.data; 
3

Co o tworzeniu zdarzenie od klasy Manager, coś podobnego zdarzenia RequestChangeSpecialData. Manager uruchamia zdarzenie, a SomeClass zmieni instancję SpecialData.

public class SomeClass 
{ 
    private Manager _m; 

    public Manager M 
    { 
     get { return _m} 
     set 
     { 
      // register/unregister event on property assignment 
      if(_m != null) 
       _m.RequestChangeSpecialData -= RequestChangeSpecialData; 

      _m = value; 

      if(_m != null) 
       _m.RequestChangeSpecialData += RequestChangeSpecialData; 

     } 
    } 

    public SpecialData Data { get; private set; } 

    private void RequestChangeSpecialData(object sender, ChangeSpecialDataEventArgs e) 
    { 
     // set the new reference 
     Data = e.SpecialData; 
    } 

} 

public class Manager 
{ 
    public void DoSomething() 
    { 
     // the manager class wants to do something, and wants to change the SpecialData instance.., so it fires the event RequestChangeSpecialData 


     SpecialData data = new SpecialData(); 

     // if the event is bound. 
     if(RequestChangeSpecialData != null) 
      RequestChangeSpecialData(this, new ChangeSpecialDataEventArgs(data)); 
    } 

    public event EventHandler<ChangeSpecialDataEventArgs> RequestChangeSpecialData; 
} 

public class ChangeSpecialDataEventArgs : EventArgs 
{ 
    public SpecialData Data {get; private set; } 

    public ChangeSpecialDataEventArgs(SpecialData Data) 
    { 
     Data = data; 
    } 
} 

NIETESTOWANY (napisał w notatniku)

Teraz Manager jest w stanie zmienić właściwość SpecialData. W ten sposób menedżer nie jest zależny od interfejsu lub zespołu SomeClass /.

+0

miał zamiar opublikować opcję wydarzenia –

Powiązane problemy