Skip to content

Instantly share code, notes, and snippets.

@jokokko
Created June 5, 2019 11:35
Show Gist options
  • Save jokokko/775279e5361f7978aa21b8f096fc9ab8 to your computer and use it in GitHub Desktop.
Save jokokko/775279e5361f7978aa21b8f096fc9ab8 to your computer and use it in GitHub Desktop.
Marten & rehydrating instances of types generated via Roslyn
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