Использование метода расширения для типа Enum приводит к ошибке компиляции (метод расширения недоступен) [дубликат]

Вопрос или проблема

Я пишу юнит-тесты для методов расширения, определенных для типа перечисления. Это тест

namespace ABC.ACSUnitySDKTest
{
    [TestFixture]
    public class AudioStreamSampleRateExTests
    {
        [Test]
        public void ToHz_16000Hz_ReturnsCorrectValue()
        {
            var result = AudioStreamSampleRate.Hz_16000.ToHz(); // <-- ОШИБКА! .ToHz() не определен!
            Assert.That(result, Is.EqualTo(16000));
        }
    }
}

Полное сообщение об ошибке:

CS1061 ‘AudioStreamSampleRate’ не содержит определения для
‘ToHz’ и не найдено доступного метода расширения ‘ToHz’, принимающего первый
аргумент типа ‘AudioStreamSampleRate’ (не хватает директивы using или ссылки на сборку?)

Но метод расширения определен, и компилятор C# уже должен это видеть:

namespace ABC
{
    internal static class AudioStreamSampleRateEx
    {
        public static int ToHz(this AudioStreamSampleRate sampleRate)
        {
            return sampleRate switch
            {
                AudioStreamSampleRate.Hz_16000 => 16000,
                AudioStreamSampleRate.Hz_22050 => 22050,
                AudioStreamSampleRate.Hz_24000 => 24000,
                AudioStreamSampleRate.Hz_32000 => 32000,
                AudioStreamSampleRate.Hz_44100 => 44100,
                AudioStreamSampleRate.Hz_48000 => 48000,
                _ => throw new NotImplementedException()
            };
        }
    }
}

Так почему компилятор C# не может увидеть метод расширения .ToHz()?

Примечание: Нам не нужно добавлять директиву ‘using’, потому что они находятся в одном пространстве имен. В любом случае, я добавил директиву ‘using’, и это не решило проблему.

Я понял, почему компилятор C# не может видеть метод расширения. Модификатор доступа internal в классе метода расширения AudioStreamSampleRateEx не позволяет этому классу и, следовательно, методу расширения быть доступными в тестовом классе AudioStreamSampleRateExTests.

Чтобы исправить это, я добавил этот атрибут:

[assembly: InternalsVisibleTo("ACSUnitySDKTest")]

в верхней части файла, в котором был определен класс ‘internal’. Этот атрибут делает внутренние типы и члены сборки, в которой этот атрибут объявлен, видимыми для другой сборки, в данном случае для сборки “ACSUnitySDKTest”.

Проблема решена!

Обновление: Другие упомянули, что я могу заменить модификатор доступа ‘internal’ на ‘public’. Да, это может решить проблему, но использование ‘internal’ является дизайнерским решением, принятым другими, и я не должен его изменять.

Ответ или решение

Для решения проблемы с доступом к методу расширения, определенному для типа перечисления (enum), необходимо учитывать особенности доступа к внутренним (internal) членам классов в C#. Давайте подробно разберем суть проблемы и предложенные решения.

Проблема: Ошибка компиляции при использовании метода расширения

При написании юнит-тестов для методов расширения, определенных для перечисления AudioStreamSampleRate, возникает ошибка компиляции:

CS1061 'AudioStreamSampleRate' does not contain a definition for 'ToHz' and no accessible extension method 'ToHz' accepting a first argument of type 'AudioStreamSampleRate' could be found (are you missing a using directive or an assembly reference?)

Причиной этой ошибки является то, что метод расширения объявлен в классе с модификатором доступа internal, что ограничивает его видимость только в пределах текущей сборки. Ваша тестовая сборка, ACSUnitySDKTest, не имеет доступа к методам и типам, объявленным как internal в другой сборке.

Решение: Использование InternalsVisibleTo

Для того чтобы сделать методы и типы internal видимыми в других сборках, можно использовать атрибут InternalsVisibleTo. Этот атрибут позволяет явно указать, какие другие сборки могут видеть ваши внутренние члены. В вашем случае, чтобы разрешить доступ к методу ToHz, необходимо добавить следующий код в файл, содержащий определение класса:

[assembly: InternalsVisibleTo("ACSUnitySDKTest")]

Это позволит сборке ACSUnitySDKTest видеть все внутренние члены сборки, где объявлен класс AudioStreamSampleRateEx.

Альтернативное решение: Изменение модификатора доступа

Другим вариантом, чтобы решить проблему, является изменение модификатора доступа с internal на public. Однако, как вы упомянули, это может быть нежелательным в силу существующих архитектурных решений, и такие изменения могут быть подвержены критике со стороны команды.

Заключение

В итоге, использование атрибута InternalsVisibleTo является оптимальным решением для вашей ситуации. Оно позволяет сохранить модификатор internal, что может быть важным для поддержания инкапсуляции и безопасности вашего кода. Таким образом, вы сможете тестировать внутренние члены без необходимости их публичного объявления.

Пользуясь этим подходом, вы сможете избежать ошибочных пониманий, связанных с доступом к методам расширения, и обеспечить целостность дизайна вашего приложения, следуя лучшим практикам программирования в C#.

Оцените материал
Добавить комментарий

Капча загружается...