Skip to content

Examples

beakona edited this page Nov 30, 2023 · 20 revisions

Simple scenario - inferred interface type

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print() => this.aspect1.Print();
}

Explicitly defined interface type

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface(typeof(IPrintable))]
   private readonly PersonPrinterV1 aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print() => ((IPrintable)this.aspect1).Print();
}

Ad-hoc adapter pattern - part1

In this example PersonPrinterV1 does not implement IPrintable but does have all members that are required by that interface.

Manually written source:

interface IPrintable
{
   void Print();
}

class PersonPrinterV1
{
   void Print() { ... }
}

public partial class Person
{
   [BeaKona.AutoInterface(typeof(IPrintable))]
   private readonly PersonPrinterV1 aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person : IPrintable
{
   void IPrintable.Print() => this.aspect1.Print();
}

Ad-hoc adapter pattern - part2

In this example PersonPrinterV1 does not implement IPrintable but does have some members that are required by that interface but not all.

Manually written source:

interface IPrintable
{
   void Print();
   void Print2();
}

class PersonPrinterV1
{
   void Print() { ... }
}

public partial class Person
{
   [BeaKona.AutoInterface(typeof(IPrintable), AllowMissingMembers = true, MemberMatch = BeaKona.MemberMatchTypes.Public)]
   private readonly PersonPrinterV1 aspect1 = new PersonPrinterV1();

   public void Print2() { ... }
}

Auto-generated accompanying source:

partial class Person : IPrintable
{
   void IPrintable.Print() => this.aspect1.Print();
}

Recursive interface types

Manually written source:

interface IPrintable
{
   void Print();
}
interface IPrintableEx : IPrintable
{
   void PrintEx();
}

public partial class Person
{
   [BeaKona.AutoInterface(typeof(IPrintableEx), IncludeBaseInterfaces = true)]
   private readonly PersonPrinterV1 aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person : IPrintableEx, IPrintable
{
   void IPrintable.Print() => ((IPrintable)this.aspect1).Print();
   void IPrintableEx.PrintEx() => ((IPrintableEx)this.aspect1).PrintEx();
}

Single interface - multiple backers

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1 = new PersonPrinterPart1();

   [BeaKona.AutoInterface]
   private readonly IPrintable aspect2 = new PersonPrinterPart2();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print()
   {
      this.aspect1.Print();
      this.aspect2.Print();
   }
}

Multiple interfaces

Manually written source:

interface IPrintable
{
   void Print();
}

interface IScannable
{
   void Scan();
}

public partial class Person : IPrintable, IScannable
{
   [BeaKona.AutoInterface(typeof(IPrintable))]
   [BeaKona.AutoInterface(typeof(IScannable))]
   private readonly Printer aspect1 = new Printer();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print() => ((IPrintable)this.aspect1).Print();
   void IScannable.Scan() => ((IScannable)this.aspect1).Scan();
}

Resolving appropriate reference

Manually written source:

public interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   private IPrintable Aspect1
   {
      get
      {
         return condition ? myPersonPrinterV1 : myPersonPrinterV2;
      }
   }
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print() => this.Aspect1.Print();
}

Custom member implementation - part1

Manually written source:

public interface IPrintable
{
   void Print();
   void Align();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1 = new PersonPrinterV1();

   void IPrintable.Print()
   {
      //custom implementation which will prevent auto-generation
   }
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Align() => this.aspect1.Align();
}

Custom member implementation - part2

Manually written source:

public interface IPrintable
{
   void Print();
   void Align();
}

public partial class Person
{
   [BeaKona.AutoInterface(MemberMatch = BeaKona.MemberMatchTypes.Public)]
   private readonly IPrintable aspect1 = new PersonPrinterV1();

   public void Print()
   {
      //custom implementation which will prevent auto-generation
   }
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Align() => this.aspect1.Align();
}

Methods, properties, indexers, events

Manually written source:

interface ITest
{
   int Age { get; }
   int this[in int a, int b = 5] { get; set; }

   event EventHandler<EventArgs> Done;

   void Method1(int a, out int b, ref int c, in int d, params int[] e);
   void Method2(int a = 1);
}

public partial class Person : ITest
{
   [BeaKona.AutoInterface]
   private readonly ITest aspect1 = new PersonTest();
}

Auto-generated accompanying source:

partial class Person
{
   int ITest.Age => this.aspect1.Age;

   int ITest.this[in int a, int b]
   {
      get => this.aspect1[in a, b];
      set => this.aspect1[in a, b] = value;
   }

   event System.EventHandler<System.EventArgs> ITest.Done
   {
      add => this.aspect1.Done += value;
      remove => this.aspect1.Done -= value;
   }

   void ITest.Method1(int a, out int b, ref int c, in int d, params int[] e)
        => this.aspect1.Method1(a, out b, ref c, in d, e);

   void ITest.Method2(int a = 1) => this.aspect1.Method2(a);
}

Class, record, struct

Manually written source:

public interface IPrintable
{
   void Print();
}

public partial record PersonR : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1 = new RecordPrinter();
}

public partial class PersonC : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1 = new ClassPrinter();
}

public partial struct PersonS : IPrintable
{
   public PersonS(IPrintable aspect1) => this.aspect1 = aspect1;

   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1;
}

Auto-generated accompanying source:

partial record PersonR
{
   void IPrintable.Print() => this.aspect1.Print();
}
partial class PersonC
{
   void IPrintable.Print() => this.aspect1.Print();
}
partial struct PersonS
{
   void IPrintable.Print() => this.aspect1.Print();
}

Full template from string

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface(TemplateLanguage = "scriban",
        TemplateBody = "customizable template definition")]
   private readonly IPrintable? aspect1 = null;
}

Auto-generated accompanying source:

partial class Person
{
   customizable template definition
}

More complete scriban template can be found on template page.

Full template from file

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   // add file mytemplate.scriban in your VS project
   // and set it's build action to: 'C# analyzer additional file'
   [BeaKona.AutoInterface(TemplateFileName = "mytemplate.scriban")]
   private readonly IPrintable? aspect1 = null;
}

Auto-generated accompanying source:

partial class Person
{
   customizable template definition
}

Partial template

Partial template can be defined inline (from string) or from file.

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   [BeaKona.AutoInterfaceTemplate(BeaKona.AutoInterfaceTargets.Method,
          Filter="regex member name matcher", Body="customizable template1 definition")]
   [BeaKona.AutoInterfaceTemplate(BeaKona.AutoInterfaceTargets.Method,
          Filter="another name matcher", Body="template2")]
   [BeaKona.AutoInterfaceTemplate(BeaKona.AutoInterfaceTargets.PropertyGetter,
          Filter="propery1", Body="template3")]
   private readonly IPrintable? aspect1 = null;
}

Auto-generated accompanying source:

partial class Person
{
   //member is generated using default template because
   //no custom implementation is matched
   void IPrintable.Print() => this.aspect1.Print();
}

Enum AutoInterfaceTargets definition:

[Flags]
public enum AutoInterfaceTargets : byte
{
   Method = 0x01,
   PropertyGetter = 0x02,
   PropertySetter = 0x04,
   IndexerGetter = 0x08,
   IndexerSetter = 0x10,
   EventAdder = 0x20,
   EventRemover = 0x40,
   Property = PropertyGetter | PropertySetter,
   Indexer = IndexerGetter | IndexerSetter,
   Event = EventAdder | EventRemover,
   Getter = PropertyGetter | IndexerGetter,
   Setter = PropertySetter | IndexerSetter,
   All = Method | Property | Indexer | Event,
}

Async

Manually written source:

interface ITest
{
   Task Method1Async();
   Task<int> Method2Async();

   ValueTask Method3Async();
   ValueTask<int> Method4Async();
}

public partial class Person : ITest
{
   [BeaKona.AutoInterface]
   private readonly ITest aspect1 = new Test();

   [BeaKona.AutoInterface]
   private readonly ITest aspect2 = new Test();
}

Auto-generated accompanying source:

partial class Person
{
   async Task ITest.Method1Async()
   {
      await this.aspect1.Method1Async();
      await this.aspect2.Method1Async();
   }

   async Task<int> ITest.Method2Async()
   {
      await this.aspect1.Method2Async();
      return await this.aspect2.Method2Async();
   }

   async ValueTask ITest.Method3Async()
   {
      await this.aspect1.Method3Async();
      await this.aspect2.Method3Async();
   }

   async ValueTask<int> ITest.Method4Async()
   {
      await this.aspect1.Method4Async();
      return await this.aspect2.Method4Async();
   }
}

Value tuples

Manually written source:

interface IPrintable
{
   void Print((int x, int y) position);
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print((int x, int y) position) => this.aspect1.Print(position);
}

Type casting

Manually written source:

interface IPrintable
{
   void Print();
}

interface IPrintableEx : IPrintable
{
   void PrintEx();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface(typeof(IPrintable))]
   private readonly IPrintableEx aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print() => ((IPrintable)this.aspect1).Print();
}

Conflicting type argument name

Manually written source:

interface ITest
{
   T F<T>(IEnumerable<T> elements);
}

public partial class Person<T> : ITest
{
   [BeaKona.AutoInterface]
   private readonly ITest aspect1 = new Test();
}

Auto-generated accompanying source:

partial class Person<T>
{
   T1 ITest.F<T1>(IEnumerable<T1> elements) => this.aspect1.F<T1>(elements);
}

Assembly alias

Manually written source:

extern alias alias1;

public partial class Person : alias1::Some.IPrintable
{
   [BeaKona.AutoInterface]
   private readonly alias1::Some.IPrintable aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

extern alias alias1;

partial class Person
{
   void alias1::Some.IPrintable.Print() => this.aspect1.Print();
}

Nested types

Manually written source:

namespace Scope
{
   public class Wrapper
   {
      public interface IPrintable
      {
         void Print();
      }
   }
}

public partial class Person : Scope.Wrapper.IPrintable
{
   [BeaKona.AutoInterface]
   private readonly Scope.Wrapper.IPrintable aspect1 = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person
{
   void Scope.Wrapper.IPrintable.Print() => this.aspect1.Print();
}

Verbatim names

Manually written source:

interface IPrintable
{
   void Print();
}

public partial class Person : IPrintable
{
   [BeaKona.AutoInterface]
   private readonly IPrintable @object = new PersonPrinterV1();
}

Auto-generated accompanying source:

partial class Person
{
   void IPrintable.Print() => this.@object.Print();
}