Подтвердить что ты не робот

Как сделать свойство protected и внутренним в С#?

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

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 из любой точки сборки, но только разрешить ее устанавливать производными классами. Я пытался сделать заголовки только внутренними, но защищенный не считается более ограничительным, чем внутренним. Есть ли способ сделать заголовки внутренними, а его набор доступа - защищенным и внутренним?

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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, который должен быть именно тем, что вы хотите.

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

Ответ 5

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

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

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

Ответ 6

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

И это правда, что вы не можете сделать это в одной строке, как многие, в том числе и я, хотел бы, но с некоторой ловкостью он на 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);
        }
    }
}

Ответ 7

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