Skip to content

Instantly share code, notes, and snippets.

@robashton
Created April 4, 2011 20:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robashton/902388 to your computer and use it in GitHub Desktop.
Save robashton/902388 to your computer and use it in GitHub Desktop.
The model we're analysing
Instruction[] dynamicMethodCalls = ExtractDynamicMethodCallInstructions();
if (dynamicMethodCalls.Length == 0) { return; }
Instruction[] cachedReflectedFields = ExtractInitialReflectedCachedFieldReferenceInstructions();
if (cachedReflectedFields.Length == 0) { return; }
CREATE TABLE Users
(
Id int Identity
Username varchar(255)
SomeId int
)
public Instruction[] ExtractDynamicMethodCallInstructions()
{
return method.Body.Instructions
.Where(x => x.OpCode.Code == Mono.Cecil.Cil.Code.Callvirt)
.Where(x => x.Operand is MemberReference && ((MemberReference)(x.Operand)).Name == "Invoke")
.ToArray();
}
public Instruction[] ExtractInitialReflectedCachedFieldReferenceInstructions()
{
return method.Body.Instructions
.Where(x => x.OpCode.Code == Code.Ldsfld && x.Next.OpCode.Code == Code.Brtrue_S)
.Where(x=> ((FieldReference)x.Operand).IsCachedReflectionField())
.ToArray();
}
public static bool IsCachedReflectionField(this FieldReference definition)
{
var baseType = definition.FieldType.Resolve().BaseType;
return baseType.FullName == typeof (System.Runtime.CompilerServices.CallSite).FullName;
return false;
}
[Test]
public void Simple_Query_Against_Table_Results_In_String_Property_With_Constant_Being_Discovered()
{
var scanner = new ModelScanner();
var model = scanner.CreateModelFromAssembly<Users>();
var table = model.Table("Users");
var property = table.Column("Username");
Assert.That(property.Type, Is.EqualTo(typeof(string)));
}
var references = cachedReflectedFields
.Select(field => field.ParseToFieldReferenceCreation())
.Reverse<string>()
.ToList<string>();
public static string ParseToFieldReferenceCreation(this Instruction fieldReference)
{
Instruction current = fieldReference;
while(current != null && current.OpCode.Code != Code.Ldstr)
{
current = current.Next;
}
return (string)current.Operand;
}
[0]: {IL_0000: nop}
[1]: {IL_0001: ldsfld System.Runtime.CompilerServices.CallSite`1<System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site1}
[2]: {IL_0006: brtrue.s IL_0046}
[3]: {IL_0008: ldc.i4.0}
[4]: {IL_0009: ldstr "FindByUsername"}
[5]: {IL_000e: ldnull}
[6]: {IL_000f: ldtoken Simple.Data.Generation.Tests.Model.Users}
[7]: {IL_0014: call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)}
[8]: {IL_0019: ldc.i4.2}
[9]: {IL_001a: newarr Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo}
[10]: {IL_001f: stloc.1}
[11]: {IL_0020: ldloc.1}
[12]: {IL_0021: ldc.i4.0}
[13]: {IL_0022: ldc.i4.0}
[14]: {IL_0023: ldnull}
[15]: {IL_0024: call Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,System.String)}
[16]: {IL_0029: stelem.ref}
[17]: {IL_002a: ldloc.1}
[18]: {IL_002b: ldc.i4.1}
[19]: {IL_002c: ldc.i4.3}
[20]: {IL_002d: ldnull}
[21]: {IL_002e: call Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,System.String)}
[22]: {IL_0033: stelem.ref}
[23]: {IL_0034: ldloc.1}
[24]: {IL_0035: call System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,System.String,System.Collections.Generic.IEnumerable`1<System.Type>,System.Type,System.Collections.Generic.IEnumerable`1<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)}
[25]: {IL_003a: call System.Runtime.CompilerServices.CallSite`1<!0> System.Runtime.CompilerServices.CallSite`1<System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>>::Create(System.Runtime.CompilerServices.CallSiteBinder)}
[26]: {IL_003f: stsfld System.Runtime.CompilerServices.CallSite`1<System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site1}
[27]: {IL_0044: br.s IL_0046}
[28]: {IL_0046: ldsfld System.Runtime.CompilerServices.CallSite`1<System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site1}
[29]: {IL_004b: ldfld !0 System.Runtime.CompilerServices.CallSite`1<System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>>::Target}
[30]: {IL_0050: ldsfld System.Runtime.CompilerServices.CallSite`1<System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site1}
[31]: {IL_0055: ldsfld System.Runtime.CompilerServices.CallSite`1<System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site2}
[32]: {IL_005a: brtrue.s IL_008f}
[33]: {IL_005c: ldc.i4.0}
[34]: {IL_005d: ldstr "Users"}
[35]: {IL_0062: ldtoken Simple.Data.Generation.Tests.Model.Users}
[36]: {IL_0067: call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)}
[37]: {IL_006c: ldc.i4.1}
[38]: {IL_006d: newarr Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo}
[39]: {IL_0072: stloc.1}
[40]: {IL_0073: ldloc.1}
[41]: {IL_0074: ldc.i4.0}
[42]: {IL_0075: ldc.i4.0}
[43]: {IL_0076: ldnull}
[44]: {IL_0077: call Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,System.String)}
[45]: {IL_007c: stelem.ref}
[46]: {IL_007d: ldloc.1}
[47]: {IL_007e: call System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder::GetMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,System.String,System.Type,System.Collections.Generic.IEnumerable`1<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)}
[48]: {IL_0083: call System.Runtime.CompilerServices.CallSite`1<!0> System.Runtime.CompilerServices.CallSite`1<System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>>::Create(System.Runtime.CompilerServices.CallSiteBinder)}
[49]: {IL_0088: stsfld System.Runtime.CompilerServices.CallSite`1<System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site2}
[50]: {IL_008d: br.s IL_008f}
[51]: {IL_008f: ldsfld System.Runtime.CompilerServices.CallSite`1<System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site2}
[52]: {IL_0094: ldfld !0 System.Runtime.CompilerServices.CallSite`1<System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>>::Target}
[53]: {IL_0099: ldsfld System.Runtime.CompilerServices.CallSite`1<System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>> Simple.Data.Generation.Tests.Model.Users/<CreateSomeViewModel>o__SiteContainer0::<>p__Site2}
[54]: {IL_009e: ldarg.0}
[55]: {IL_009f: ldfld System.Object Simple.Data.Generation.Tests.Model.Users::db}
[56]: {IL_00a4: callvirt !2 System.Func`3<System.Runtime.CompilerServices.CallSite,System.Object,System.Object>::Invoke(!0,!1)}
[57]: {IL_00a9: ldstr "bob"}
[58]: {IL_00ae: callvirt !3 System.Func`4<System.Runtime.CompilerServices.CallSite,System.Object,System.String,System.Object>::Invoke(!0,!1,!2)}
[59]: {IL_00b3: stloc.0}
[60]: {IL_00b4: br.s IL_00b6}
[61]: {IL_00b6: ldloc.0}
[62]: {IL_00b7: ret}
public void PopulateDataModel(DataModel model)
{
definition.Methods
.Select(method =>new MethodInspector(method)).ToList()
.ForEach(inspector => inspector.PopulateDataModel(model));
}
public class Users
{
private dynamic db = Database.Open();
public dynamic CreateSomeViewModel()
{
return db.Users.FindByUsername("bob");
}
public dynamic CreateAnotherViewModel()
{
return db.Users.FindBySomeId(4);
}
}
public class ModelScanner
{
public DataModel CreateModelFromAssembly<T>()
{
var model = new DataModel();
var assembly = typeof(T).Assembly;
var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assembly.Location);
assemblyDefinition.MainModule.Types
.Select(type => new TypeInspector(type))
.ToList()
.ForEach(inspector => inspector.PopulateDataModel(model));
return model;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment