Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overridable component settings via ApplyX #951

Open
matkoch opened this issue Jun 24, 2022 · 1 comment
Open

Allow overridable component settings via ApplyX #951

matkoch opened this issue Jun 24, 2022 · 1 comment

Comments

@matkoch
Copy link
Member

matkoch commented Jun 24, 2022

Description

  • Adapt GetTarget to support InvocationExpression
    (((configurator.Body as InvocationExpression).Expression as MemberExpression).Expression as ConstantExpression).Value
    
  • Introduce new ApplyX method with Expression<Configure<T>> (no overload, since ambiguous)
  • Add assertion in existing Apply method and check if configurator.Target/Method is declared by interface
  • Use GetAllMembers to get quasi-override for original member similar as in ValueInjectionAttributeBase.GetMemberValue<T>
  • Maybe base calls via .Apply<T>(...)

JetBrains Rider-nuke-common – SettingsEntity Apply cs-2022-06-25-Y7ugiORf@2x

JetBrains Rider-nuke-common – SettingsEntity Apply cs-2022-06-25-FJP1g6oM@2x

Usage Example

interface ICompile : INukeBuild
{
    Target Compile => _ => _
        .Executes(() =>
        {
            var settings = new DotNetBuildSettings()
                .ApplyX(x => x.CompileSettings);
        });

    Configure<DotNetBuildSettings> CompileSettings => _ => _;
}

interface ICompileWithSomething : INukeBuild
{
    Configure<DotNetBuildSettings> ICompile.CompileSettings => _ => _
        .SetProperty("foo", "bar");
}

class Build : ICompileWithSomething
{
}
@bitbonk
Copy link
Contributor

bitbonk commented Jul 2, 2022

With the help of @matkoch I managed to get this method working:

public static TSettings Apply<TComponent, TSettings>(this TSettings settings, Expression<Func<TComponent, Configure<TSettings>>> configurator)
{
     var target = configurator.GetTarget();
     var memberInfo = configurator.GetMemberInfo();
     var config = memberInfo.GetValue<Configure<TSettings>>(target);
     return config.Invoke(settings);
}

Which would have been called like this:

DotNetBuild(_ => _
    .Apply(CompileSettingsBase)
    .Apply((ICompileEx x) => CompileSettings));

Where ICompileX looked like this:

public interface ICompileEx : ICompile
{
     Configure<DotNetBuildSettings> ICompile.CompileSettings => _ =>
            _.SetProperty("TestPropertyFromICompileEx.Key", "TestPropertyFromICompileEx.Value");
}

And Build had this:

Configure<DotNetBuildSettings> ICompile.CompileSettings => _ => _.SetProperty("TestPropertyFromBuild.Key", "TestPropertyFromBuild.Value");

The end result was that only TestPropertyFromBuild was present in the final settings and the ICompileX "layer" was ignored (not called).
This is probably because they layers are not virtual.

Using GetValueNonVirtual instead of GetValue in the new Apply method resulted in no layers being called at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants