Непоследовательная доступность: тип возврата меньше, чем метод - PullRequest
0 голосов
/ 25 октября 2018

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

Позвольте мне дать подробное объяснение: у меня есть статический класс Line и структура LingSegment в Line, пользователи могут определять свои собственные LineSegment в Line, и мне нужно убедиться, что между линейными сегментами нет конфликта.

Архитектура выглядит следующим образом:

public static class Line {
    private struct LineSegment {
        public LineSegment(int start, int end) {
            Start = start;
            End = end;
        }

    public readonly int Start;
    public readonly int End;
    }

   // User created LineSegment
   static public LineSegment Segment1() {
       return new LineSegment(1, 2);
   }

   static public LineSegment Segment2() {
       return new LineSegment(3, 6);
   }
}

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

int start = Line.Segment1.Start;
int end = Line.Segment1.End;

Причина, по которой я задаю LineSegment как private, заключается в следующем: я хочу, чтобы пользователи создавали LineSegment и получали к нему доступ только через статические функции в Line, например Segment1, Segment2.Так что я могу добавить модульный тест, используя отражение, чтобы получить все методы в Line, и получить начало и конец всех сегментов линии, тогда я могу судить, существует ли конфликт между сегментами линии.

Если LineSegment общедоступен, пользователи могут взломать свой код, просто используя: new Line.LineSegment(2, 5), и я не могу обнаружить его с помощью модульного теста.Я не хочу, чтобы они создавали LineSegment за пределами Line.

Но в C # запрещено делать LineSegment из-за несовместимой доступности .Есть ли какое-либо решение, которое может удовлетворить мое требование?Спасибо!

Ответы [ 3 ]

0 голосов
/ 25 октября 2018

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

public interface ILineSegment
{
    int Start { get; }
    int End { get; }
}

, а затем ваш класс:

public static class Line
{
    private struct LineSegment : ILineSegment
    {
        public int Start { get; }
        public int End { get; }

        public LineSegment(int start, int end)
        {
            Start = start;
            End = end;
        }
    }

    // User created LineSegment
    static public ILineSegment Segment1()
    {
        return new LineSegment(1, 2);
    }

    static public ILineSegment Segment2()
    {
        return new LineSegment(3, 6);
    }

Обратите внимание, что возвращаемые значения LineSegment1 и LineSegment2 были изменены с LineSegment (который является закрытым, ине может быть возвращен открытым методом) в ILineSegment, который является открытым и может быть возвращен.

0 голосов
/ 28 октября 2018

После сравнения и выяснения некоторых мнений, наконец, я решил использовать Environment.StackTrace.Contains для удовлетворения моих требований.

public static class Line {
    public struct LineSegment {
        public LineSegment(int start, int end) {
            if (!Environment.StackTrace.Contains("MyNamespace.Line") || !Environment.StackTrace.Contains("UnitTest")) {
                throw new InvalidOperationException("Outside code is not allowed to call its constructor. Please construct your property in this file refering to the example.");
            }

            Start = start;
            End = end;
        }

        public readonly int Start;
        public readonly int End;
    }

   // User created LineSegment
   static public LineSegment Segment1() {
       return new LineSegment(1, 2);
   }

   static public LineSegment Segment2() {
       return new LineSegment(3, 6);
   }
}
0 голосов
/ 25 октября 2018

как насчет: дать им доступ, но предупредить их ...

    public static class Line {
        public struct LineSegment {
            [Obsolete("DO NOT USE THIS DIRECTLY...")]
            public LineSegment(int start, int end) {
                Start = start;
                End = end;
            }

        public readonly int Start;
        public readonly int End;
        }

       // User created LineSegment
       static public LineSegment Segment1() {
           return _CreateSegment(1, 2);
       }

       static public LineSegment Segment2() {
           return _CreateSegment(3, 6);
       }

       static private LineSegment _CreateSegment(int start,int end) {
//we don't want to trigger the warning ...
#pragma warning disable 618
           return new LineSegment(3, 6);
#pragma warning restore 618
       }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...