How might I list the properties of a generic type within an aspect?

I want to translate the properties of a generic type constraint of the base type implemented by my target type into fields on my target via an aspect, but I'm struggling to figure out how to keep everything in compile-land so Metalama is happy. I've tried the following:
var propertiesOnType = builder.Target.BaseType.TypeParameters[0].ToType().GetProperties();
var propertiesOnType = builder.Target.BaseType.TypeParameters[0].ToType().GetProperties();
But this yields an error:
The instance of Type cannot be accessed at compile time because it represents a run-time object. Try using meta.RunTime() to convert this object to its run-time value.
Ok, fair enough:
var propertiesOnType = meta.RunTime(builder.Target.BaseType.TypeParameters[0].ToType().GetProperties());
var propertiesOnType = meta.RunTime(builder.Target.BaseType.TypeParameters[0].ToType().GetProperties());
Same error:
Error LAMA0041: The index of Type cannot be accessed at compile type because it represents a run-time object. Try using meta.RunTime() to convert this object to its run-time value.
I noticed that the documentation on ToType indicates it yields a run-time value, but GetType reads "The exact runtime type of the current instance" so I tried that:
var propertiesOnType = builder.Target.BaseType.TypeParameters[0].GetType().GetProperties();
var propertiesOnType = builder.Target.BaseType.TypeParameters[0].GetType().GetProperties();
This will actually work but it doesn't appear to actually list the properties I'm looking for and instead lists the properties of each of the properties on a single property (maybe?) - see the first attached picture. Ok, so what if I specifically try to pull out the names and types themselves?
var p = new Dictionary<string, Type>();
foreach(var prop in builder.Target.BaseType.TypeParameters[0].GetType().GetProperties())
{
p.Add(prop.Name, prop.PropertyType);
}

//Put them into a method so I can see what's in there:
builder.Advice.IntroduceMethod(builder.Target, nameof(DebugMethod), IntroductionScope.Instance,
OverrideStrategy.Ignore,
b =>
{
b.Accessibility = Accessibility.Private;
}, args: new
{
test = propertyNamesAndTypes
});

[Template]
private void DebugMethod([CompileTime] Dictionary<string, Type> test)
{
foreach (var p in test)
{
var sb = new InterpolatedStringBuilder();
sb.AddText("Name: ");
sb.AddExpression(p.Key);
sb.AddText(", Type: ");
sb.AddExpression(p.Value);

Console.WriteLine(sb.ToValue());
}
}
var p = new Dictionary<string, Type>();
foreach(var prop in builder.Target.BaseType.TypeParameters[0].GetType().GetProperties())
{
p.Add(prop.Name, prop.PropertyType);
}

//Put them into a method so I can see what's in there:
builder.Advice.IntroduceMethod(builder.Target, nameof(DebugMethod), IntroductionScope.Instance,
OverrideStrategy.Ignore,
b =>
{
b.Accessibility = Accessibility.Private;
}, args: new
{
test = propertyNamesAndTypes
});

[Template]
private void DebugMethod([CompileTime] Dictionary<string, Type> test)
{
foreach (var p in test)
{
var sb = new InterpolatedStringBuilder();
sb.AddText("Name: ");
sb.AddExpression(p.Key);
sb.AddText(", Type: ");
sb.AddExpression(p.Value);

Console.WriteLine(sb.ToValue());
}
}
Now this one was odd because Metalama first insisted that I needed to install the Microsoft.CodeAnalysis project first to proceed. After installing that, it read:
Threw 'InvalidOperationException' when applied to 'MyType.DebugMethod()': The type 'Metalama.Framework.Engine.CodeModel.CompilationModel' cannot be used at run-time.
Any suggestions of how I can extract the name and type of each of the properties of these concrete types populating the generic types of a base class so I might then introduce fields based on the values to the target type? Thank you!
No description
1 Reply
Xaniff
Xaniff13mo ago
Ok, upon digging into it - I understand now why I get the values I do on the picture - it's reflecting a type of TEntity and not actually the type that's used at runtime. Until a moment ago, I'd assumed that at compile time, the compiler would replace the generic types with the runtime types, but Bing has corrected me that the compiler only determines legality and the constructed generic type isn't created until runtime. As such, this question is generally moot as I'm going to have to think of an entirely different way to make the types available to the aspect.