There is an alternative described in this blog post with sample code on GitHub, which uses an undocumented attribute to be used in the assembly that accesses the private/internal members.
Note however the following:
- This is not documented and not recommended
- You cannot compile it directly, instead you need to use Roslyn
- It also appears to ignore access even to private members which is definitely something to be very careful with
It might however be useful for example when dealing with dynamic assemblies etc, see example below.
The Code
Here is what needs to be done, in your code add the IgnoresAccessChecksToAttribute
as in the following code (make sure it is NOT under any other namespace or it will not work):
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
AssemblyName = assemblyName;
}
public string AssemblyName { get; }
}
}
and then anywhere in your code add the attribute as in:
[assembly: IgnoresAccessChecksTo("AssemblyToAccess")]
or in the csproj file:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute">
<_Parameter1>AssemblyToAccess</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
Compilation
Compilation is tricky as it cannot be compiled with standard means, instead it has to be called via Roslyn, there should be many resources available on how to compile dynamically with Roslyn, but here is the particular details that needs to be done for this compilation to work:
var compilationOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication).
WithMetadataImportOptions(MetadataImportOptions.All);
var topLevelBinderFlagsProperty = typeof(CSharpCompilationOptions)
.GetProperty("TopLevelBinderFlags", BindingFlags.Instance | BindingFlags.NonPublic);
// 22 is the value of the undocumented member BinderFlags.IgnoreAccessibility
topLevelBinderFlagsProperty.SetValue(compilationOptions, (uint)1 << 22);
Usage in Assembly Builder
One legitimate use is when compiling dynamically assemblies that needs access to internal classes, see my answer there for sample code.
InternalsVisibleTo
. If you're considering using it, then it's even more unclear than it was before what, exactly, you consider "unclean" or "messy" about it. – Birdsongassembly
attribute, which of course only has to be specified once in the project. In fact, it's not even valid to try to apply it at the class level. – Birdsong