Skip to content

Instantly share code, notes, and snippets.

@stakx
Last active July 20, 2018 08:15
Show Gist options
  • Save stakx/994331287188ffd6459f6c988fc72506 to your computer and use it in GitHub Desktop.
Save stakx/994331287188ffd6459f6c988fc72506 to your computer and use it in GitHub Desktop.
Demonstrates the special `IgnoresAccessChecksToAttribute` of .NET 4.6+ and .NET Core 1.0+
using System;
using System.Reflection;
using System.Reflection.Emit;
// Note that this is `internal` and regularly shouldn't be accessible from other assemblies:
internal sealed class Hellower
{
internal void SayHello()
{
Console.WriteLine("Hello!");
}
}
// The following code will implement this interface in a dynamic assembly such that it will call the above `SayHello` method:
public interface ITrigger
{
void Do();
}
class Program
{
static void Main()
{
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicAssembly");
// class IgnoresAccessChecksToAttribute
var attributeTypeBuilder = moduleBuilder.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute", TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.Class, typeof(Attribute));
var attributeTypeUsageAttrBuilder = new CustomAttributeBuilder(
con: typeof(AttributeUsageAttribute).GetConstructor(new[] { typeof(AttributeTargets) }),
constructorArgs: new object[] { AttributeTargets.Assembly },
namedProperties: new[] { typeof(AttributeUsageAttribute).GetProperty("AllowMultiple") },
propertyValues: new object[] { true });
attributeTypeBuilder.SetCustomAttribute(attributeTypeUsageAttrBuilder);
var attributeTypeFieldBuilder = attributeTypeBuilder.DefineField("assemblyName", typeof(string), FieldAttributes.Private | FieldAttributes.InitOnly);
var attributeTypeCtorBuilder = attributeTypeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard | CallingConventions.HasThis, new[] { typeof(string) });
var attributeTypeCtorIL = attributeTypeCtorBuilder.GetILGenerator();
attributeTypeCtorIL.Emit(OpCodes.Ldarg_0);
attributeTypeCtorIL.Emit(OpCodes.Ldarg_1);
attributeTypeCtorIL.Emit(OpCodes.Ldfld, attributeTypeFieldBuilder);
attributeTypeCtorIL.Emit(OpCodes.Ret);
var attributeTypeGetterBuilder = attributeTypeBuilder.DefineMethod("get_AttributeName", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(string), null);
var attributeTypeGetterIL = attributeTypeGetterBuilder.GetILGenerator();
attributeTypeGetterIL.Emit(OpCodes.Ldarg_0);
attributeTypeGetterIL.Emit(OpCodes.Ldfld, attributeTypeFieldBuilder);
attributeTypeGetterIL.Emit(OpCodes.Ret);
var attributeTypePropertyBuilder = attributeTypeBuilder.DefineProperty("AttributeName", PropertyAttributes.None, typeof(string), null);
attributeTypePropertyBuilder.SetGetMethod(attributeTypeGetterBuilder);
var attributeType = attributeTypeBuilder.CreateTypeInfo().AsType();
// [assembly: IgnoresAccessChecksToAttribute("ConsoleApp1")]
// TODO: replace "ConsoleApp1" with the name of the project containing this code
var assemblyAttrBuilder = new CustomAttributeBuilder(attributeType.GetConstructor(new[] { typeof(string) }), new object[] { "ConsoleApp1" });
assemblyBuilder.SetCustomAttribute(assemblyAttrBuilder); // Try uncommenting this line and see the difference!
// class Trigger : ITrigger
var triggerTypeBuilder = moduleBuilder.DefineType("Trigger", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class);
var doMethodBuilder = triggerTypeBuilder.DefineMethod("Do", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig, CallingConventions.Standard | CallingConventions.HasThis, typeof(void), null);
var doMethodIL = doMethodBuilder.GetILGenerator();
doMethodIL.Emit(OpCodes.Newobj, typeof(Hellower).GetConstructor(Type.EmptyTypes));
doMethodIL.EmitCall(OpCodes.Callvirt, typeof(Hellower).GetMethod("SayHello", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), null);
doMethodIL.Emit(OpCodes.Ret);
triggerTypeBuilder.AddInterfaceImplementation(typeof(ITrigger));
var triggerType = triggerTypeBuilder.CreateTypeInfo().AsType();
var trigger = (ITrigger)Activator.CreateInstance(triggerType);
trigger.Do();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment