C #: Защищенные переменные внутри общего класса могут быть доступны из другого подкласса этого общего класса.Могу ли я предотвратить это? - PullRequest
0 голосов
/ 22 ноября 2018

Скажем, у меня есть универсальный класс Foo, у которого есть защищенная переменная

public class Foo<T> 
{ 
    protected bool knowsFu; 
}

У меня также есть 2 подкласса: Bar и Pipe

public class Bar : Foo<Bar> {}

public class Pipe : Foo<Pipe> {}

Это на самом делеВозможно ли мне получить доступ к KnowFu в трубе FROM Bar, например:

public class Bar : Foo<Bar> 
{
    void UpdateFuInOtherClass(Pipe p)
    {
        p.knowsFu = false;
    }
}

Это предполагаемое поведение?(Если это так, какой будет сценарий использования?)

Есть ли способ для меня, чтобы другие Foo-подклассы не могли изменить / достичь защищенной переменной внутри моего текущего подкласса?

Более конкретно: Я использую универсальный класс для реализации Singleton-Pattern: https://en.wikipedia.org/wiki/Singleton_pattern

Однако в настоящее время я могу получить доступ к любой защищенной переменной экземпляра синглтона, пока яЯ в другом синглтоне.Есть ли способ предотвратить это?

РЕДАКТИРОВАТЬ: Может быть уместно заметить, что защищенная переменная (knowFu) на самом деле также STATIC.

EDIT2: Хорошо, возможнопример был abit слишком общим ... вот как я на самом деле сейчас его реализую:

зачем использовать Singleton?A: Платформа, над которой я работаю, - это Unity3D, в которой шаблон часто используется

У меня есть типизированный абстрактный класс SingletonBehaviour

public abstract class SingletonBehaviour<T> where T : MonoBehaviour
{
    public static T Instance { get { return instance; } }

    protected static T instance { get; private set; } }

    // Loading is done through Unitys Awake-Method
}

Один из Singleton-Объектами, которые я использую, является APIManager

public class APIManager : SingletonBehaviour<APIManager>
{
    // Methods like SendHTTPPost(), HTTPGet(), etc.
}

Однако, поскольку большинство моих проектов нуждаются в некоторой лучшей реализации API, чем то, что я сейчас делаю:

public class ProjectAAPIManager : APIManager 
{
    // Overriding Instance so my return value is not APIManager but instead ProjectAAPIManager
    public static new ProjectAAPIMamager Instance { get { return (ProjectAAPIManager)instance; } }
}

Это ^ причина, по которой моя (внутренняя) переменная экземпляра защищена, а не закрыта.

Однако из-за этого любой другой SingletonBehaviour в моем проекте теперь может обращаться к (внутренней) переменной экземпляра на моемProjectAAPIManager

public class GameController : SingletonBehaviour<GameController> 
{
    private void AMethod()
    {
         // Accessing inner variable instead of public one
         ProjectAAPIManager.instance.DoSomething();
    }
}

Поскольку это всего лишь геттер, в настоящее время это не имеет большого значения.Но что, если мне также понадобится доступ к сеттеру в моем подклассе?

Кроме того: стоило ли бы вообще использовать мой APIManager?

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Ваш вопрос не что иное, как недоумение.Как сделать защищенный член недоступным для производного класса?Что ж, хорошее начало не делает его защищенным.

protected по определению именно то, что вы не хотите, так что не используйте его!Вместо этого используйте private.

Если вы спрашиваете, как сделать его доступным только для чтения при доступе из производных типов, у вас есть два варианта:

  1. Объявить его как доступный только для чтения в базекласс, если это возможно.
  2. Вместо этого используйте защищенное свойство с частным установщиком.

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

0 голосов
/ 22 ноября 2018

У вас не должно быть классов, реализующих ваш общий одноэлементный класс.В противном случае, по умолчанию, ваши защищенные поля будут доступны подклассам (это то, что делает ключевое слово «защищено»)

Вместо этого вы должны сделать что-то вроде этого:

class Program
{
    static void Main(string[] args)
    {
        var barInstance = Foo<Bar>.GetInstance();
    }
}

public class Foo<T> where T : new()
{
    protected bool knowsFu;

    private static T _instance;

    public static T GetInstance()
    {
        if (_instance == null)
            _instance = new T();

        return _instance;
    }
}

public class Bar
{
    public Bar()
    {
    }
}

Редактировать 1:

Чтобы использовать одноэлементный, не следует заставлять другой класс реализовывать одноэлементное поведение (это не так, как работает одноэлементный паттерн).Чтобы использовать те же классы, что и во втором примере, вы должны сделать что-то вроде этого.

public class SingletonBehaviour<T> where T : new()
{    
    public static T Instance 
    { 
        get 
        {
            if(instance == null)
                instance = new T()
            return instance; 
        } 
    } 
    private static T instance { get; set; } 
}

public class APIManager // This class should not inherit from the SingletonBehavior class
{
    // Methods like SendHTTPPost(), HTTPGet(), etc.
}

public class ProjectAAPIManager : APIManager 
{
    public ProjectAAPIManager GetInstance() => SingletonBehavior<ProjectAAPIManager>.Instance();
}
...