Last active
July 20, 2018 08:15
-
-
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+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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