dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.36k stars 9.99k forks source link

error CS1503: Argument 2: cannot convert from 'method group' to 'EventCallback' #12226

Closed gurunathancs1991 closed 5 years ago

gurunathancs1991 commented 5 years ago

Description:

When using EventCallBack<T>, I countered an issue about error CS1503: Argument 2: cannot convert from 'method group' to 'EventCallback'

I have checked other github blogs which related to this, mostly reported that, this has been fixed in preview 7 version. Right now, i have tested with preview 7 build but could not get resolve it.

Here the link which i checked earlier. https://github.com/aspnet/AspNetCore/issues/10077 https://github.com/aspnet/AspNetCore/issues/8385 https://github.com/aspnet/AspNetCore/pull/10730 https://github.com/aspnet/AspNetCore/issues/10077

Whether any syntax changes required to resolve in preview 7 version?

Screenshot: image

Please find my component structure:

Rendering Page [Index razor page]


      @page "/"
      @using GenericEvent.Shared.Models;
      @inject IJSRuntime jsruntime;

    <MyGenComponent Data="@MyData">
        <Events>
        <NonGenericEvents EventTwo="@Event2"></NonGenericEvents>
        <GenericEvents EventOne="@EventOne"></GenericEvents>
         </Events>

    </MyGenComponent>

    @functions {
        public List<string> MyData = new List<string>() { "a", "b", "c", "d" };

        public void Event2(EventArguments args)
       {

       }

       public async Task EventOne(EventArgsData<string> data)
       {
        //dummy call
        await jsruntime.InvokeAsync<string>("call");
       }
      }

MyGenComponent.razor


    @using GenericEvent.Shared.Models;

    @typeparam T;

    <div>
        <ul>
            @ChildContent
        </ul>
    </div>

    @functions {
    [Parameter]
    protected RenderFragment ChildContent { get; set; }

    [Parameter]
    public IEnumerable<T> Data { get; set; }
    }

Events.razor


      @using Microsoft.AspNetCore.Components;

      @inherits ComponentBase

     <CascadingValue Value="@this">
        @ChildContent
    </CascadingValue>

     @functions{

    [Parameter]
    protected RenderFragment ChildContent { get; set; }

    public GenericEvents<object> GenEvents { get; set; }

    public NonGenericEvents NonGenEvents { get; set; }

     }

GenericEvents.razor


      @using Microsoft.AspNetCore.Components;
      @using GenericEvent.Shared.Models;

       @typeparam TValue

      <CascadingValue Value="@this">

     </CascadingValue>

     @functions{

     [Parameter]
    public EventCallback<EventArgsData<TValue>> EventOne { get; set; }

    }

NonGenericEvents.razor

    @using Microsoft.AspNetCore.Components;
     @using GenericEvent.Shared.Models;

    <CascadingValue Value="@this">

    </CascadingValue>

    @functions{

      [Parameter]
      public EventCallback<EventArguments> EventTwo { get; set; }

      }

To Reproduce

Clone this Github repository and run the application

https://github.com/gurunathancs1991/BlazorGenericEvents

We are also expecting the solution for this thread too

https://github.com/aspnet/AspNetCore/issues/12116

Additional context


C:\Users\GurunathanA>dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview7-012814
 Commit:    efad165932

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.17763
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.0.100-preview7-012814\

Host (useful for support):
  Version: 3.0.0-preview7-27912-14
  Commit:  4da6ee6450

.NET Core SDKs installed:
  1.1.13 [C:\Program Files\dotnet\sdk]
  1.1.14 [C:\Program Files\dotnet\sdk]
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.502 [C:\Program Files\dotnet\sdk]
  2.1.602 [C:\Program Files\dotnet\sdk]
  2.1.700 [C:\Program Files\dotnet\sdk]
  2.2.202 [C:\Program Files\dotnet\sdk]
  2.2.300 [C:\Program Files\dotnet\sdk]
  3.0.100-preview7-012814 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview4-19216-03 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview7.19363.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 1.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview4-27615-11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download
SQL-MisterMagoo commented 5 years ago

A workaround (maybe even the correct way):

<GenericEvents TValue="string" EventOne="@EventOne"></GenericEvents>
EdCharbeneau commented 5 years ago

I agree that this still seems like an issue as creating verbose markup when handling events (without databinding).

Take the InputSelect for example. ValueChanged either requires T to be defined or a lambda expression within ValueChanged. Compounding the problem is ValueExpression which is also required, this is leading to some very clumsy looking markup @(()=>. This isn't going to be the DX people expect when coming from jQuery, WebForms or even React.

<p>Current value: @form.MyProperty</p>

<EditForm Model="form">
    <InputSelect ValueChanged="@DoThing" 
                 T="string"
                 ValueExpression="@(()=> form.MyProperty)">
        <option value="0">0</option>
        <option value="100">100</option>
        <option value="200">200</option>
        <option value="300">300</option>
    </InputSelect>
</EditForm>

@code {
    MyForm form = new MyForm();

    void DoThing(string s)
    {
        form.MyProperty = s;
    }

    public class MyForm
    {
        public string MyProperty { get; set; }
    }
}
   <InputSelect ValueChanged="@((string s) => DoThing(s))"
                 ValueExpression="@(()=> form.MyProperty)">
        <option value="0">0</option>
        <option value="100">100</option>
        <option value="200">200</option>
        <option value="300">300</option>
    </InputSelect>
pranavkm commented 5 years ago

From what I can tell, the problem is that the compiler does not use the the generic type parameter for type inference in method calls. Here's a fairly trivial example:


public void Foo()
{
    Tester<int>(2, TestAction);
    // This fails complaining about type inference
    Tester<int>(2, CreateDelegate(TestAction));
}

public void TestAction(int x) { }

public void Tester<T>(T value, Action<T> input) { }

public static Action<T> CreateDelegate<T>(Action<T> action) => action;

We effectively get the same code when we code-gen a Razor file like this:

<InputSelect ValueChanged="ChangedInt" />

@code {
    public void ChangedInt(int value)
    {
    }
}
using Microsoft.AspNetCore.Components;

namespace razor1.Pages
{
    public class Index : Microsoft.AspNetCore.Components.ComponentBase
    {
        protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder)
        {
            __Blazor.razor1.Pages.Index.TypeInference.CreateInputSelect_0(builder, 0, 1, Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this,
                           ChangedInt
            ));
        }

        public void ChangedInt(int value)
        {
        }
    }
}
namespace __Blazor.razor1.Pages.Index
{
    internal static class TypeInference
    {
        public static void CreateInputSelect_0<T>(global::Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder, int seq, int __seq0, global::Microsoft.AspNetCore.Components.EventCallback<T> __arg0)
        {
            builder.OpenComponent<global::Microsoft.AspNetCore.Components.Forms.InputSelect<T>>(seq);
            builder.AddAttribute(__seq0, "ValueChanged", __arg0);
            builder.CloseComponent();
        }
    }
}

The compiler fails the type inferrence, picks the wrong overload for EventCallback.Factory.Create and generates the method group conversion error reported here.

From playing around, one of the ways to solve this would be to modify the code in TypeInference to pass the Action<T> in and produce the EventCallback<T> in there. This works well, but we now have the pain of having to code-gen an overload per overload of EventCallback.Factory.Create<T>. Changing the code-gen is going to be fairly involved, so I'm sending it back to triage to consider for a later release.


Workarounds that have been pointed out by others in the thread that work:

1) Specify the type parameter

<InputSelect T="int" ValueChanged="ChangedInt" />

(I filed an issue to do a pass over blazor input elements to consider renaming T to TValue or something slightly better)

2) Use a delegate or perform an explicit cast

<InputSelect ValueChanged="(int x) => ChangedInt(x)" />

<InputSelect ValueChanged="(Action<int>)ChangedInt" />
mkArtakMSFT commented 5 years ago

Thanks for contacting us, @gurunathancs1991. As @pranavkm has pointed out, you will have to go with one of the provided workarounds here. Type inference will always have limitations and it's unfortunate that this is one of them.

srg1204 commented 5 years ago

EdCharbeneau commented on 23 Jul wrote: but this solution is not working with ASP.NET Core and Blazor updates in .NET Core 3.0 Preview 9.19424.4

Current value: @form.MyProperty

@code { MyForm form = new MyForm();

void DoThing(string s)
{
    form.MyProperty = s;
}

public class MyForm
{
    public string MyProperty { get; set; }
}

} <InputSelect ValueChanged="@((string s) => DoThing(s))" ValueExpression="@(()=> form.MyProperty)">

<option value="100">100</option>
<option value="200">200</option>
<option value="300">300</option>

srg1204 commented 5 years ago

Sorry my mistake: EdCharbeneau was OK: the solution works very well