Как сделать свойство защищенным И внутренним в C #? - PullRequest
28 голосов
/ 02 июня 2009

Вот мой сокращенный абстрактный класс:

abstract class Report {

    protected internal abstract string[] Headers { get; protected set; }
}

Вот производный класс:

class OnlineStatusReport : Report {

    static string[] headers = new string[] {
        "Time",
        "Message"
    }

    protected internal override string[] Headers {
        get { return headers; }
        protected set { headers = value; }
    }

    internal OnlineStatusReport() {
        Headers = headers;
    }
}

Идея состоит в том, что я хочу иметь возможность вызывать Report.Headers из любой точки сборки, но разрешить его установку только производными классами. Я попытался сделать Headers только внутренним, но защищенный не считается более строгим, чем внутренний. Есть ли способ сделать заголовки внутренними, а их набор доступа защищенными И внутренними?

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

Ответы [ 7 ]

31 голосов
/ 02 июня 2009

Это невозможно в C #.

Для полноты картины это поддерживается в IL (модификатор доступа к семейству и сборке).

16 голосов
/ 03 июня 2009

Что плохого в том, чтобы обнародовать геттер? Если вы объявите свойство как

public string[] Headers { get; protected set; }

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

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

protected string[] Headers { get; set; }
internal string[] I_Headers { get { return Headers; } }

Конечно, некрасиво украшать имя этим префиксом I_. Но это довольно странный дизайн. Выполнение какого-либо искажения имени во внутреннем свойстве - это способ напомнить себе (или другим разработчикам), что свойство, которое они используют, неортодоксально. Кроме того, если позже вы решите, что смешанная доступность не является правильным решением вашей проблемы, вы будете знать, какие свойства нужно исправить.

6 голосов
/ 11 октября 2011

Вы можете использовать внутренний явно реализованный интерфейс:

internal interface IReport
{
    string[] Headers { get; }
}

abstract class Report : IReport
{
    protected abstract string[] Headers { get; protected set; }

    string[] IReport.Headers
    {
        get { return Headers; }
    }
}

class OnlineStatusReport : Report
{
    static string[] headers = new string[] { "Time", "Message" };

    protected internal override string[] Headers
    {
        get { return headers; }
        protected set { headers = value; }
    }

    internal OnlineStatusReport()
    {
        Headers = headers;
    }
}

Теперь вы получаете внутренний доступ к сборке, в которой определен IReport, что должно быть именно тем, что вы хотите.

Реализация интерфейсов в явном виде не является широко известной стратегией, но она решает множество проблем.

6 голосов
/ 02 июня 2009

Я бы сохранил модификатор доступа как защищенный и имел бы внутренний вспомогательный метод.

protected override string[] Headers {
    get { return headers; } // Note that get is protected
    set { headers = value; }
}

internal SetHeadersInternal(string[] newHeaders)
{
    headers = newHeaders;
}

Но почему-то это пахнет так, как-то должно быть рефакторинг. Внутренний всегда то, что я бы использовал экономно, потому что это может привести к очень грязной архитектуре, где все каким-то образом использует все остальное внутри сборки, но, конечно, всегда есть исключения.

3 голосов
/ 07 декабря 2012

CLR поддерживает концепцию защищенного И внутреннего (известную как доступ к семейству и сборке), и C # ДОЛЖЕН реализовать / раскрыть эту концепцию. C #, вероятно, должен позволять следующее:

internal string[] Header { get; protected set; }

В этом случае ИНТЕРСЕКТ / И оба модификатора видимости должны быть установлены для установщика свойств и позволять вам читать заголовки из любой точки одной сборки, но устанавливать их только из производных классов в одной сборке.

2 голосов
/ 18 ноября 2017

Начиная с C # 7.2, существует конструкция private protected ( ссылка ). Он не позволяет читать с поля (таким образом, не выполняет в точности то, что намеревается OP), но стоит взять добычу.

2 голосов
/ 13 июля 2010

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

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

//Code below is 100% tested

/* FROM ProtectedAndInternal.dll */

namespace ProtectedAndInternal
{
    public class MyServiceImplementationBase
    {
        protected static class RelevantStrings
        {
            internal static string AppName = "Kickin' Code";
            internal static string AppAuthor = "Scott Youngblut";
        }
    }

    public class MyServiceImplementation : MyServiceImplementationBase
    {
        public void PrintProperties()
        {
            // WORKS PERFECTLY BECAUSE SAME ASSEMBLY!
            Console.WriteLine(RelevantStrings.AppAuthor);
        }
    }

    public class NotMyServiceImplementation
    {
        public void PrintProperties()
        {
            // FAILS - NOT THE CORRECT INHERITANCE CHAIN
            // Error CS0122: 'ProtectedAndInternal.MyServiceImplementationBase.Relevant' is inaccessible due to its protection level
            // Console.WriteLine(MyServiceImplementationBase.RelevantStrings.AppAuthor);
        }
    }
}



/* From AlternateAssemblyService.dll which references ProtectedAndInternal.dll */

namespace AlternateAssemblyService
{
    public class MyServiceImplementation : MyServiceImplementationBase
    {
        public void PrintProperties()
        {
            // FAILS - NOT THE CORRECT ASSEMBLY
            // Error CS0117: 'ProtectedAndInternal.MyServiceImplementationBase.RelevantStrings' does not contain a definition for 'AppAuthor'
            // Console.WriteLine(RelevantStrings.AppAuthor);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...