Skip to content

Instantly share code, notes, and snippets.

@mouadcherkaoui
Forked from breezhang/a.cs
Created April 11, 2019 13:17
Show Gist options
  • Save mouadcherkaoui/c092b8d25569dc32fe9f91391dfc9938 to your computer and use it in GitHub Desktop.
Save mouadcherkaoui/c092b8d25569dc32fe9f91391dfc9938 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using ObjectDumper;
using Xunit;
namespace Classdynamic.BK5
{
public class Foo
{
public string Bar(int value)
{
return value.ToString("##,###");
}
}
public static class Plus
{
public static T Dump<T>(this T value)
{
using (var debugWriter = new DebugWriter())
return value.Dump("ooHelloworldxx", debugWriter);
}
}
public class Test
{
private delegate void Fx(int a);
[Fact]
public void Main()
{
object foo = new Foo();
// We have an instance of something and want to call a method with this signature on it :
// public string Bar(int value);
Console.WriteLine("Cast and Direct method call");
{
string result = ((Foo) foo).Bar(42);
result.Dump();
}
Console.WriteLine("Create a lambda closing on the local scope.");
{
// Useless but i'll do it at the end by manual il generation
Func<int, string> func = i => ((Foo) foo).Bar(i);
string result = func(42);
result.Dump();
}
Console.WriteLine("Using MethodInfo.Invoke");
{
MethodInfo method = foo.GetType().GetMethod("Bar");
var result = (string) method.Invoke(foo, new object[] {42});
result.Dump();
}
Console.WriteLine("Using the dynamic keyword");
{
var dynamicFoo = (dynamic) foo;
var result = (string) dynamicFoo.Bar(42);
result.Dump();
}
Console.WriteLine("Using CreateDelegate");
{
MethodInfo method = foo.GetType().GetMethod("Bar");
var func = (Func<int, string>) Delegate.CreateDelegate(typeof (Func<int, string>), foo, method);
string result = func(42);
result.Dump();
}
Console.WriteLine("Create an expression and compile it to call the delegate on one instance.");
{
MethodInfo method = foo.GetType().GetMethod("Bar");
ConstantExpression thisParam = Expression.Constant(foo);
ParameterExpression valueParam = Expression.Parameter(typeof (int), "value");
MethodCallExpression call = Expression.Call(thisParam, method, valueParam);
Expression<Func<int, string>> lambda = Expression.Lambda<Func<int, string>>(call, valueParam);
Func<int, string> func = lambda.Compile();
string result = func(42);
result.Dump();
}
Console.WriteLine("Create an expression and compile it to a delegate that could be called on any instance.");
{
// Note that in this case "Foo" must be known at compile time, obviously in this case you want
// to do more than call a method, otherwise just call it !
Type type = foo.GetType();
MethodInfo method = type.GetMethod("Bar");
ParameterExpression thisParam = Expression.Parameter(type, "this");
ParameterExpression valueParam = Expression.Parameter(typeof (int), "value");
MethodCallExpression call = Expression.Call(thisParam, method, valueParam);
Expression<Func<Foo, int, string>> lambda = Expression.Lambda<Func<Foo, int, string>>(call, thisParam,
valueParam);
Func<Foo, int, string> func = lambda.Compile();
string result = func((Foo) foo, 42);
result.Dump();
}
Console.WriteLine(
"Create a DynamicMethod and compile it to a delegate that could be called on any instance.");
{
// Same thing as the previous expression sample. Foo need to be known at compile time and need
// to be provided to the delegate.
Type type = foo.GetType();
MethodInfo method = type.GetMethod("Bar");
var dynamicMethod = new DynamicMethod("Bar_", typeof(string), new[] { typeof(Foo), typeof(int) }, true);
ILGenerator il = dynamicMethod.GetILGenerator();
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Ret);
var func = (Func<Foo, int, string>)dynamicMethod.CreateDelegate(typeof(Func<Foo, int, string>));
string result = func((Foo)foo, 42);
result.Dump();
//check static diff this + medthod >haha<
Func<int, string> x = X;
var fucks = x.Method;
var fx = new Fx(Y);
var fucky = fx.Method;
var d1 = new DynamicMethod("xxx", typeof(string), new[] { typeof(int) });
var ilG = d1.GetILGenerator();
ilG.DeclareLocal(typeof (string));
ilG.Emit(OpCodes.Ldarg_0);
ilG.Emit(OpCodes.Call, fucks);
ilG.Emit(OpCodes.Ldarg_0);
ilG.Emit(OpCodes.Call, fucky);
ilG.Emit(OpCodes.Ret);
var f = (Func<int,string>)d1.CreateDelegate(typeof (Func<int, string>));
var s =f(4);
Console.WriteLine(s);
}
Console.WriteLine("Simulate closure without closures and in a lot more lines...");
{
Type type = foo.GetType();
MethodInfo method = type.GetMethod("Bar");
// The Foo class must be public for this to work, the "skipVisibility" argument of
// DynamicMethod.CreateDelegate can't be emulated without breaking the .Net security model.
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("MyAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder module = assembly.DefineDynamicModule("MyModule");
TypeBuilder tb = module.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public);
FieldBuilder fooField = tb.DefineField("FooInstance", type, FieldAttributes.Public);
MethodBuilder barMethod = tb.DefineMethod("Bar_", MethodAttributes.Public, typeof (string),
new[] {typeof (int)});
ILGenerator il = barMethod.GetILGenerator();
il.DeclareLocal(typeof (string));
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldfld, fooField);
il.Emit(OpCodes.Ldarg_1); // arg
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Ret);
Type closureType = tb.CreateType();
object instance = closureType.GetConstructors().Single().Invoke(new object[0]);
closureType.GetField(fooField.Name).SetValue(instance, foo);
MethodInfo methodOnClosureType = closureType.GetMethod("Bar_");
var func = (Func<int, string>) Delegate.CreateDelegate(typeof (Func<int, string>), instance,
closureType.GetMethod("Bar_"));
string result = func(42);
result.Dump();
}
}
public static string X(int i)
{
return "xxoo" + i;
}
public static void Y(int a)
{
Console.WriteLine("add some code stuff!" +a);
}
}
}
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Dynamic;
using System.Runtime.CompilerServices;
class Test
{
public static object GetDynamicValue(dynamic o, string name)
{
CallSite<Func<CallSite, object, object>> site
= CallSite<Func<CallSite, object, object>>.Create
(Binder.GetMember(CSharpBinderFlags.None, name,
typeof(Test), new CSharpArgumentInfo[]
{ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
return site.Target(site, o);
}
static void Main()
{
Console.WriteLine(GetDynamicValue("hello", "Length"));
}
}
from http://stackoverflow.com/questions/2508828/where-to-learn-about-vs-debugger-magic-names/2509524#2509524
These are undocumented implementation details of the compiler, and subject to change at any time.
However, since I'm a nice guy, here are some of those details:
If you have an unused local variable that the optimizer removes, we emit debug info for it anyway into the PDB. We stuck the suffix __Deleted$ onto such variables so that the debugger knows that they were in source code but not represented in the binary.
Temporary variable slots allocated by the compiler are given names with the pattern CS$X$Y, where X is the "temporary kind" and Y is the number of temporaries allocated so far. The temporary kinds are:
0 --> short lived temporaries
1 --> return value temporaries
2 --> temporaries generated for lock statements
3 --> temporaries generated for using statements
4 --> durable temporaries
5 --> the result of get enumerator in a foreach
6 --> the array storage in a foreach
7 --> the array index storage in a foreach.
Temporary kinds between 8 and 264 are additional array index storages for multidimensional arrays.
Temporary kinds above 264 are used for temporaries involving the fixed statement fixing a string.
Special compiler-generated names are generated for:
1 --> the iterator state ("state")
2 --> the value of current in an iterator ("current")
3 --> a saved parameter in an iterator
4 --> a hoisted 'this' in an iterator ("this")
5 --> a hoisted local in an iterator
6 --> the hoisted locals from an outer scope
7 --> a hoisted wrapped value ("wrap")
8 --> the closure class instance ("locals")
9 --> the cached delegate instance ("CachedAnonymousMethodDelegate")
a --> the iterator instance ("iterator")
b --> an anonymous method
c --> anonymous method closure class ("DisplayClass")
d --> iterator class
e --> fixed buffer struct ("FixedBuffer")
f --> anonymous type ("AnonymousType")
g --> initializer local ("initLocal")
h --> query expression temporary ("TransparentIdentifier")
i --> anonymous type field ("Field")
j --> anonymous type type parameter ("TPar")
k --> auto prop field ("BackingField")
l --> iterator thread id
m --> iterator finally ("Finally")
n --> fabricated method ("FabricatedMethod")
o --> dynamic container class ("SiteContainer")
p --> dynamic call site ("Site")
q --> dynamic delegate ("SiteDelegate")
r --> com ref call local ("ComRefCallLocal")
s --> lock taken local ("LockTaken")
The pattern for generating magical names is: P<N>C__SI where:
P is CS$ for cached delegates and display class instances, empty otherwise.
N is the original name associated with the thing, if any
C is the character 1 through s listed above
S is a descriptive suffix ("current", "state", and so on) so that you don't have to have the table above memorized when reading the metadata.
I is an optional unique number
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment