Open Jcparkyn opened 2 years ago
To summarize some of the possible fixes for this, any of the following should be possible, but they each have issues to work around:
Action<T>
instead of EventCallback<T>
in the generated TypeInference methodE.g.,
public static void CreateMyComponent_0<TItem>(TItem __arg0, object __component, Action<TItem> __arg1) // other params omitted
{
__builder.OpenComponent<global::Test.MyComponent<TItem>>(seq);
__builder.AddAttribute(__seq0, "Item", __arg0);
__builder.AddAttribute(__seq1, "MyEvent", EventCallback.Factory.Create<TItem>(__component, __arg1));
__builder.CloseComponent();
}
The big issue here is that it wouldn't work by default if the user passes an EventCallback<T>
directly, rather than a delegate.
EventCallback.Factory.CreateInferred
E.g., in the generated BuildRenderTree
method, replace
global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, x => {})
with
global::Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, x => {}, 1) // 1 would come from the value of the first `T` parameter.
The issues with this approach are:
1
in the example above) would need to be stored in a local variable, to avoid evaluating it twice.CreateInferred
would need additional overloads to handle e.g. passing an already-constructed EventCallback<T>
T
(as opposed to e.g., Func<T>
).new()
It is possible to get around most of the issues with the approaches above by using target-typed new()
expressions inside BuildRenderTree
. EventCallback<T>
does not currently have constructors that would make this possible, so the options would be either:
EventCallback<T>
. This could potentially be a breaking change, and I assume there's a reason they don't exist already?EventCallback<T>
and provide the necessary constructors. This would need to be used as the parameter for the TypeInference
method. E.g., private class EventCallbackTypeInference<T>
{
public EventCallback<T> Handler { get; }
// Note: These would probably use EventCallback.Factory instead of new()
public EventCallbackTypeInference(IHandleEvent? receiver, Action<T> handler) => Handler = new(receiver, handler);
public EventCallbackTypeInference(IHandleEvent? receiver, Func<T, object> handler) => Handler = new(receiver, handler);
public EventCallbackTypeInference(IHandleEvent? receiver, EventCallback<T> handler) => Handler = handler;
}
Then, in the type inference method:
static void CreateMyComponent_0<TItem>(TItem __arg0, EventCallbackTypeInference<TItem> __arg1) //etc
{
__builder.OpenComponent<global::Test.MyComponent<TItem>>(seq);
__builder.AddAttribute(__seq0, "Item", __arg0);
__builder.AddAttribute(__seq1, "MyEvent", __arg1.Handler);
__builder.CloseComponent();
}
BuildRenderTree
can then use any of the following formats, without needing to know any of the types:
CreateMyComponent_0(3, new(this, x => { }));
CreateMyComponent_0(3, new(this, async x => { }));
CreateMyComponent_0(3, new(this, SomeMethodGroup));
CreateMyComponent_0(3, new(this, SomeMethodGroupAsync));
CreateMyComponent_0(3, new(this, x => x + 1));
var ec = new EventCallback<int>();
CreateMyComponent_0(3, new(this, ec));
Any updates on this?
This is an intentional duplicate of dotnet/razor-compiler#150 and https://github.com/dotnet/aspnetcore/issues/39734, which were both (as far as I can tell) closed prematurely, due to a separate (but related) issue being fixed.
Tested on SDK version
7.0.100-rc.2.22477.23
To recap the actual issue: Given the following generic component:
GenericComponent.razor
Some of the following usages fail to compile, and neither of them give error messages that adequately explain the issue:
The rules for which scenarios work here are quite confusing, and the error messages don't help to guide the user. This is a particularly big problem when using more complicated (or multiple) type arguments, which are a lot harder to type explicitly.
https://github.com/dotnet/aspnetcore/issues/39734 has some explanation of why this issue occurs.