Source generator to create ProxyClasses
$ dotnet add package Rop.ProxyGeneratorRop.ProxyGenerator is a source generator package to automatic proxy of interfaces. It can be used to provide Aspect Oriented Programming to c# via a "proxy".
The package is published in nuget as 'Rop.ProxyGenerator'
Example:I want to add to any winform control a "IControlValue" standard interface.
public interface IControlValue<T>
{
event EventHandler ControlValueChanged;
[Exclude]
T ControlValue { get; set; }
}
The interface has a common implementation but C# can't allow multiple inheritance.
To allow inject IControlValue logic to any winform control we derive a control with this syntax:
[ProxyOf("IControlValue<int>", nameof(_controlValueProxy))]
public partial class TextBoxValue : TextBox, IControlValue<int>
{
private readonly IControlValue<int> _controlValueProxy;
public TextBoxValue()
{
_controlValueProxy = new TextBoxValueAop(this);
}
private class TextBoxValueAop : ControlValueAop<TextBoxValue, int>
{
public TextBoxValueAop(TextBoxValue parent) : base(parent){}
}
}
The constructor creates the adapted logic to our class. That logic will be automaticly injected to code via rop.proxygenerator. The source generator.
The generated code will be a proxy for each IControlValue member.
// Autogenerated code for Proxy class
public partial class TextBoxValue
{
public event EventHandler ControlValueChanged{
add=>_controlValueProxy.ControlValueChanged+=value;
remove=>_controlValueProxy.ControlValueChanged-=value;
}
public virtual void OnControlValueChanged()
{
_controlValueProxy.OnControlValueChanged();
}
// Symbol 'ControlValue' excluded
}
I can "exclude" a member to force his declaration via attributes. In this case. "ControlValue" depends of the type of the control. So, I must hard code in my class
public partial class TextBoxValue{
public virtual int ControlValue
{
get => int.TryParse(base.Text, out int v) ? v : -1;
set => base.Text = value.ToString();
}
}
The ASPECT code to incorporate as proxy is derived from a abstract common logic of type ControlValueAOP
public abstract class ControlValueAop<C, T> : IControlValue<T> where C : Control, IControlValue<T>
{
public C Parent { get; }
public event EventHandler ControlValueChanged;
public virtual void OnControlValueChanged()
{
ControlValueChanged?.Invoke(this.Parent, EventArgs.Empty);
}
public virtual T ControlValue
{
get => this.Parent.ControlValue;
set => this.Parent.ControlValue = value;
}
protected ControlValueAop(C parent)
{
this.Parent = parent;
}
}
Rop.ProxyGenerator.AnnotationsAttibutes to decorate a class to contain a proxy.
[AttributeUsage(AttributeTargets.Class)]
public class ProxyOfAttribute:Attribute
{
...
public ProxyOfAttribute(Type interfacename, string fieldname,string[] exclude=null)
{
...
}
}
Attibutes to include other attributes defined in an interface
public class IncludeNextAttributesAttribute : System.Attribute {}
Attribute to Exclude a Member
public class ExcludeAttribute : Attribute { }
Attibutes to Override Members
public class OverrideNewAttribute : Attribute { }
public class OverrideNoBaseAttribute : Attribute { }
public class OverrideWithPreBaseAttribute : Attribute { }
public class OverrideWithPostBaseAttribute : Attribute { }
Attributes to force Explicit Implementation of Proxy Interface
public class ExplicitAttribute : Attribute { }
public class ExplicitOverrideNoBaseAttribute : Attribute { }
public class ExplicitOverrideWithPreBaseAttribute : Attribute { }
public class ExplicitOverrideWithPostBaseAttribute : Attribute { }
Rop.ProxyGeneratorThe source generator that create the proxy as partial class. Must be included as:
(C)2022 Ramón Ordiales Plaza