Атрибут InternalsVisibleTo не работает - PullRequest
       118

Атрибут InternalsVisibleTo не работает

69 голосов
/ 20 сентября 2008

Я пытаюсь использовать атрибут сборки InternalsVisibleTo, чтобы сделать мои внутренние классы в библиотеке классов .NET видимыми для моего проекта модульного теста. По какой-то причине я получаю сообщение об ошибке:

MyClassName недоступно из-за уровня защиты

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

Ответы [ 19 ]

95 голосов
/ 20 сентября 2008

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

[assembly: InternalsVisibleTo("MyFriendAssembly,
PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73
F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66
A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519
674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140
6E2F553073FF557D2DB6C5")]

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

39 голосов
/ 26 июля 2013

Другая возможная «ошибка»: имя сборки друга, которое вы указываете в InternalsVisibleToAttribute, должно точно соответствовать имени сборки друга, как показано в свойствах проекта друга (на вкладке «Приложение» ).

В моем случае у меня был проект Thingamajig и сопутствующий проект ThingamajigAutoTests (имена были изменены, чтобы защитить виновных), в результате которого были созданы неподписанные сборки. Я должным образом добавил атрибут [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] в файл Thingamajig \ AssemblyInfo.cs и прокомментировал атрибуты AssemblyKeyFile и AssemblyKeyName, как отмечено выше. Thingamajig Проект построен очень хорошо, но его внутренние члены упорно не обнаруживаться в проекте автотестов.

После сильных царапин я перепроверил свойства проекта ThingamajigAutoTests и обнаружил, что имя сборки было указано как "ThingamajigAutoTests.dll". Бинго - я добавил расширение «.dll» к имени сборки в атрибуте InternalsVisibleTo, и кусочки встали на свои места.

Иногда это мелочи ...

35 голосов
/ 29 августа 2010

Если ваши сборки не подписаны, но вы все равно получаете ту же ошибку, проверьте файл AssemblyInfo.cs на наличие одной из следующих строк:

[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

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

11 голосов
/ 21 апреля 2009

Стоит отметить, что если «дружеская» (тестовая) сборка написана на C ++ / CLI, а не на C # / VB.Net, то вам необходимо использовать следующее:

#using "AssemblyUnderTest.dll" as_friend

вместо ссылки на проект или обычного #using заявления. По какой-то причине это невозможно сделать в справочном интерфейсе проекта.

9 голосов
/ 10 мая 2010

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

5 голосов
/ 22 марта 2012

Вот макрос, который я использую для быстрой генерации этого атрибута. Это немного странно, но это работает. На моей машине. Когда последний подписанный двоичный файл находится в /bin/debug. Etc двусмысленность и т.д. В любом случае, вы можете увидеть, как он получает ключ, так что это даст вам подсказку. Исправить / улучшить, как позволяет время.

Sub GetInternalsVisibleToForCurrentProject()
    Dim temp = "[assembly:  global::System.Runtime.CompilerServices." + _
               "InternalsVisibleTo(""{0}, publickey={1}"")]"
    Dim projs As System.Array
    Dim proj As Project
    projs = DTE.ActiveSolutionProjects()
    If projs.Length < 1 Then
        Return
    End If

    proj = CType(projs.GetValue(0), EnvDTE.Project)
    Dim path, dir, filename As String
    path = proj.FullName
    dir = System.IO.Path.GetDirectoryName(path)
    filename = System.IO.Path.GetFileNameWithoutExtension(path)
    filename = System.IO.Path.ChangeExtension(filename, "dll")
    dir += "\bin\debug\"
    filename = System.IO.Path.Combine(dir, filename)
    If Not System.IO.File.Exists(filename) Then
        MsgBox("Cannot load file " + filename)
        Return
    End If
    Dim assy As System.Reflection.Assembly
    assy = System.Reflection.Assembly.Load(filename)
    Dim pk As Byte() = assy.GetName().GetPublicKey()
    Dim hex As String = BitConverter.ToString(pk).Replace("-", "")
    System.Windows.Forms.Clipboard.SetText(String.Format(temp, assy.GetName().Name, hex))
    MsgBox("InternalsVisibleTo attribute copied to the clipboard.")
End Sub
4 голосов
/ 20 сентября 2008

Вам необходимо использовать ключ / out: compiler при компиляции сборки-друга (сборки, которая не содержит атрибут InternalsVisibleTo).

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

3 голосов
/ 17 сентября 2014

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

3 голосов
/ 25 ноября 2015

В моем случае, используя VS.Net 2015, мне нужно было подписать ОБА сборок (если хотя бы 1 сборка должна быть подписана или вы хотите сослаться на открытый ключ вашей сборки).

Мой проект вообще не использовал подпись. Поэтому я начал добавлять ключ подписи в свою тестовую библиотеку и использовать InternalsVisibleTo-Attribute в базовой библиотеке моего проекта. Но VS.Net всегда объяснял, что не может получить доступ к методам друзей.

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

2 голосов
/ 08 октября 2016

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

  1. Вы вызываете внутренний метод, определенный в X, из другой сборки Y
  2. В сигнатуре метода используются внутренние типы, определенные в Z
  3. Затем необходимо добавить [InternalsVisibleTo] в X и в Z

Например:

// In X
internal static class XType
{
    internal static ZType GetZ() { ... }
}

// In Y:
object someUntypedValue = XType.GetZ();

// In Z:
internal class ZType { ... }

Если вы написали, как указано выше, где вы не ссылаетесь на ZType непосредственно в Y, после добавления Y в качестве друга X, вы можете быть озадачены, почему ваш код все еще не компилируется.

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

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