aloneguid / config

⚙ Config.Net - the easiest configuration framework for .NET developers. No BS.
MIT License
641 stars 85 forks source link

NativeAOT compatibility #155

Open ZimM-LostPolygon opened 10 months ago

ZimM-LostPolygon commented 10 months ago

Unfortunately, right now, Config.NET can not be used with NativeAOT, because it relies on doing runtime code generation. This is a warning I'm getting during the NativeAOT build:

ILC: Method '[Castle.Core]Castle.DynamicProxy.Generators.MethodWithInvocationGenerator.BuildProxiedMethodBody(MethodE
  mitter,ClassEmitter,INamingScope)' will always throw because: Missing method 'System.Reflection.ConstructorInfo Syste
  m.Reflection.Emit.TypeBuilder.GetConstructor(System.Type, System.Reflection.ConstructorInfo)'

And sure enough, as soon as I do the typical new ConfigurationBuilder<IMySettings>().Build() thing, the app crashes:

Unhandled Exception: System.ArgumentException: Type System.Object is not valid base type for interface proxy, because it does not have accessible parameterless constructor. Only a non-sealed class with non-private default constructor can be used as base type for interface proxy. Please use some other valid type.
   at Castle.DynamicProxy.Generators.BaseInterfaceProxyGenerator.ThrowInvalidBaseType(Type, String) + 0x5f
   at Castle.DynamicProxy.Generators.BaseInterfaceProxyGenerator.EnsureValidBaseType(Type) + 0x114
   at Castle.DynamicProxy.Generators.BaseInterfaceProxyGenerator..ctor(ModuleScope, Type, Type[], Type, ProxyGenerationOptions) + 0x77
   at Castle.DynamicProxy.Generators.InterfaceProxyWithoutTargetGenerator..ctor(ModuleScope, Type, Type[], Type, ProxyGenerationOptions) + 0x42
   at Castle.DynamicProxy.DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(Type, Type[], ProxyGenerationOptions) + 0xc3
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyTypeWithoutTarget(Type, Type[], ProxyGenerationOptions) + 0x48
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type, Type[], ProxyGenerationOptions, IInterceptor[]) + 0x10d
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type, IInterceptor) + 0xb8
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget[TInterface](IInterceptor) + 0x65
   at Config.Net.ConfigurationBuilder`1.Build() + 0x101
   at Sencae.Desktop.EmulatorRunner.Run(String[]) + 0x75
   at Sencae.Program.Main(String[] args) + 0x3c
   at Sencae.Desktop!<BaseAddress>+0x2bb067
   at Sencae.Desktop!<BaseAddress>+0x2bb0e9

One possible workaroud would be to not have to rely on dynamically creating proxies, and instead use concrete classes defined in the source code (even if it means having to write extra boilerplate code), but it seems like Config.NET doesn't support that or provides an API for doing it manually.