Metalama
Metalama copied to clipboard
Feature request: allow an aspect to introduce a new type
I'd like to be write an aspect to generate classes implementing data access interfaces. Currently (2023.1) my code won't work:
Example interface
interface IPerson
{
string Name { get; }
int Age { get; }
}
Example of the code I'd like my aspect to generate
class Person : SomeBaseClass, IPerson
{
public Person(ISomeContext context, string name, int age) : base (context)
{
this.Name = name;
this.Age = age;
}
public string Name { get; set; }
public int Age { get; set; }
}
What's working, what's not working
- I cannot create a class from scratch (can be solved by requiring the user to write an empty class stub).
- I cannot create a constructor from scratch (can probably be solved by requiring the user to write an empty constructor stub).
- I can add the interface
IPerson
toPerson
inBuildAspect
by callingbuilder.Advice.ImplementInterface()
. - I can add properties
Name
andAge
to the class by callingbuilder.Advice.IntroduceAutomaticProperty()
. - I cannot make the properties show up in the interface (somehow,
[InterfaceMember]
should be applied dynamically).
The last point is a show-stopper for what I am intending to do. I'd love to see this feature be part of a coming release of Metalama.
Hello @epsitec, thank you for submitting this issue. We will try to get back to you as soon as possible. Note to the PostSharp team, this ticket is being tracked in our dashboard under ID TP-33174.
Here is my current attempt:
public abstract class Entity<T>
where T : class
{ }
public interface IPerson
{
string Name { get; }
int Age { get; }
}
[EntityImplementation]
public class Person : Entity<IPerson>
{ }
public sealed class EntityImplementationAttribute : TypeAspect
{
public override void BuildAspect(IAspectBuilder<INamedType> builder)
{
_ = builder ?? throw new ArgumentNullException (nameof (builder));
var typeName = builder.Target.Name;
var baseType = builder.Target.BaseType
?? throw new InvalidCastException ("No base type");
if (baseType.IsGeneric == false)
{
throw new InvalidOperationException ($"Base type of {typeName} should be generic");
}
if (baseType.TypeParameters.Count != 1)
{
throw new InvalidOperationException ($"Base type of {typeName} should have one generic parameter");
}
var interfaceType = (INamedType) baseType.TypeArguments[0];
if (interfaceType.TypeKind != TypeKind.Interface)
{
throw new InvalidOperationException ($"The generic type parameter <{interfaceType.ToType ().Name}> of the base type of {typeName} should be an interface, not {interfaceType.TypeKind}");
}
var interfaceProperties = interfaceType.AllProperties;
foreach (var interfaceProperty in interfaceProperties)
{
builder.Advice.IntroduceAutomaticProperty (
builder.Target,
interfaceProperty.Name,
interfaceProperty.Type.ToType (),
OverrideStrategy.Ignore,
b => b.Accessibility = Accessibility.Public);
}
/*
builder.Advice.ImplementInterface (
builder.Target,
interfaceType,
OverrideStrategy.Ignore);
*/
}
}
To upvote a feature request please add a "me too" comment because the number of emoticon reactions is not aggregated by GitHUb.
me too
me too
me too
me too
me too
mee too
me too
me too