Created
June 5, 2019 11:35
-
-
Save jokokko/775279e5361f7978aa21b8f096fc9ab8 to your computer and use it in GitHub Desktop.
Marten & rehydrating instances of types generated via Roslyn
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
namespace Marten.Samples.GeneratedType | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var store = DocumentStore.For(c => | |
{ | |
c.Connection("cstring"); | |
c.AutoCreateSchemaObjects = AutoCreate.All; | |
}); | |
var assembly = AssemblyGenerator.Generate(); | |
var parcelType = assembly.GetType($"{nameof(GeneratedType)}.Parcel"); | |
var parcelWeight = parcelType.GetProperty("Weight"); | |
using (var session = store.OpenSession()) | |
{ | |
var parcelLight = Activator.CreateInstance(parcelType); | |
var parcelHeavy = Activator.CreateInstance(parcelType); | |
parcelWeight.SetValue(parcelLight, 100); | |
parcelWeight.SetValue(parcelHeavy, 1000); | |
session.Insert(parcelLight, parcelHeavy); | |
session.SaveChanges(); | |
} | |
var queryByWeight = typeof(Program).GetMethod(nameof(QueryGreaterThan)).MakeGenericMethod(parcelType); | |
using (var session = store.OpenSession()) | |
{ | |
var heavyParcels = (IList)queryByWeight.Invoke(null, new object[] { session, "Weight", 500 }); | |
Console.WriteLine($"Parcels: {heavyParcels.Count}"); | |
} | |
} | |
public static List<T> QueryGreaterThan<T>(IQuerySession session, string property, int minimum) | |
{ | |
var t = typeof(T); | |
var query = typeof(IQuerySession).GetMethods() | |
.Single(m => m.Name == "Query" && m.IsGenericMethodDefinition && m.GetParameters().Length == 0) | |
.MakeGenericMethod(t); | |
var where = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public) | |
.FirstOrDefault(x => x.Name == "Where").MakeGenericMethod(t); | |
var toList = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) | |
.FirstOrDefault(x => x.Name == "ToList").MakeGenericMethod(t); | |
var parameter = Expression.Parameter(typeof(T), "p"); | |
var predicate = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(Expression.PropertyOrField(parameter, property), Expression.Constant(minimum)), parameter); | |
var queryInstance = query.Invoke(session, null); | |
var enumeration = where.Invoke(null, new[] { queryInstance, predicate }); | |
var values = toList.Invoke(null, new[] {enumeration}); | |
return (List<T>)values; | |
} | |
} | |
public static class AssemblyGenerator | |
{ | |
public static Assembly Generate() | |
{ | |
var syntaxFactory = SyntaxFactory.CompilationUnit(); | |
syntaxFactory = syntaxFactory.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System"))); | |
var @namespace = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(nameof(GeneratedType))).NormalizeWhitespace(); | |
var classDeclaration = SyntaxFactory.ClassDeclaration("Parcel"); | |
classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); | |
var idDeclaration = SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("int"), "Id") | |
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) | |
.AddAccessorListAccessors( | |
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), | |
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))); | |
var weightDeclaration = SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("int"), "Weight") | |
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) | |
.AddAccessorListAccessors( | |
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), | |
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))); | |
classDeclaration = classDeclaration.AddMembers(idDeclaration, weightDeclaration); | |
@namespace = @namespace.AddMembers(classDeclaration); | |
syntaxFactory = syntaxFactory.AddMembers(@namespace); | |
var comp = CSharpCompilation.Create(Guid.NewGuid().ToString(), new[] { syntaxFactory.SyntaxTree }, GetAssemblyReferences(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); | |
using (var memStream = new MemoryStream()) | |
{ | |
comp.Emit(memStream); | |
memStream.Seek(0, SeekOrigin.Begin); | |
var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(memStream); | |
return assembly; | |
} | |
} | |
private static IEnumerable<MetadataReference> GetAssemblyReferences() | |
{ | |
var references = new MetadataReference[] | |
{ | |
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location) | |
}; | |
return references; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment