1

I have encountered a seemingly "weird" situation. Repro:

  1. Create an F# library
  2. Add a component class type, inheriting ComponentBase
  3. Override BuildRenderTree
//Comp1Base.fs
namespace ClassLibrary1

open Microsoft.AspNetCore.Components

type Comp1Base() = 
    inherit ComponentBase()

    override __.BuildRenderTree(builder) = base.BuildRenderTree(builder)
  1. Create a Blazor WASM project (C#) and reference the F# project
  2. Add a razor component to this project and inherit from the F# base component
//Comp1.razor
@inherits ClassLibrary1.Comp1Base

Now the Blazor project doesn't compile:

Error   CS0507  'Comp1.BuildRenderTree(RenderTreeBuilder)': cannot change access modifiers when overriding 'public' inherited member 'Comp1Base.BuildRenderTree(RenderTreeBuilder)' BlazorApp1  C:\Temp\qwerty\BlazorApp1\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\Comp1_razor.g.cs   85  N/A

ILSpy shows that the overridden member in F# is public, while the base member is protected:

enter image description here enter image description here

Is there a way to make it work?

Franco Tiveron
  • 2,364
  • 18
  • 34
  • In F# the default is public, unlike C# which is private. You have to specify visibility protected. – jalepi Feb 14 '22 at 01:05
  • The `protected` modifier doesn't exist in F#. I suppose making an overridden member `public` was seen as the appropriate compiler behaviour https://stackoverflow.com/questions/2390515/why-isnt-there-a-protected-access-modifier-in-f – tranquillity Feb 14 '22 at 03:15
  • 1
    Does this answer your question? [F# Public Override of Protected Methods](https://stackoverflow.com/questions/24625830/f-public-override-of-protected-methods) – Brian Berns Feb 14 '22 at 03:19
  • @user1344783 F# doesn't have protected visibility – Franco Tiveron Feb 14 '22 at 04:18
  • @tranquillity I think there shouldn't be cases where F# cannot replicate what C# can do – Franco Tiveron Feb 14 '22 at 04:20
  • @BrianBerns No it doesn't. BuildRenderTree is called by Blazor (the framework), not from the app code. Blazor generates code from razor that contains a protected override to BuildRenderTree exact name. The F# public override breaks this pattern. – Franco Tiveron Feb 14 '22 at 04:26
  • 1
    There is a separate framework https://fsbolero.io/ to use F# with Blazor. I've not used it but I would guess they have built in the necessary workarounds for this. – tranquillity Feb 14 '22 at 06:57

2 Answers2

1

I'm afraid you cannot do this in F# directly. You could write a more F#-friendly wrapper type in C# like so (untested code, for illustration purposes):

public class FSharpFriendlyComponentBase: ComponentBase
{
    readonly Action<RenderTreeBuilder> _buildRenderTree

    public FSharpFriendlyComponentBase(Action<RenderTreeBuilder> buildRenderTree) =>
        _buildRenderTree = buildRenderTree;

    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        base.BuildRenderTree(builder);
        _buildRenderTree(builder);
    }
}

This would then allow you to implement the required behavior in F#:

let myComponentBase = 
    FSharpFriendlyComponentBase(fun builder -> 
        ... your behavior here)
Asik
  • 21,506
  • 6
  • 72
  • 131
0

Somewhat late but I hope it helps:

In C# (I'm talking about C#) you can't change the access modifier when overriding a method as Microsoft Docs says.

Seyfi
  • 1,832
  • 1
  • 20
  • 35