Conversation
c75e6c9 to
ea23d19
Compare
ea23d19 to
3ff7f0f
Compare
1d4a100 to
1cf4cab
Compare
|
Another CR note: this PR changes what was previously an invariant of the system. Until now, we always knew for sure that a rendertree frame of type "Component" with After this PR, that invariant no longer holds, since the activator could return a component instance of any Loosening this invariant is beneficial for cases like testing as it means you can "mock" a child component or do shallow rendering (replace all the child components with empty things). However it's something to bear in mind in the future and not get confused about! |
| /// <inheritdoc /> | ||
| public IComponent CreateInstance(Type componentType) | ||
| { | ||
| var instance = Activator.CreateInstance(componentType); |
There was a problem hiding this comment.
Unrelated to your change, but it might be worth profiling this to see if caching the factories makes a difference.
There was a problem hiding this comment.
We only create one per Renderer so it seems very unlikely to make a difference to anything. Was there a particular reason you’re suspicious it might have an observable effect?
There was a problem hiding this comment.
Oh you mean some kind of cached activator? I’m not even sure that’s possible without Reflection.Emit (which works but is slow on WebAssembly). Do you know of a good way to implement it?
There was a problem hiding this comment.
I was going to suggest ActivatorUtiltiies.CreateFactory but that uses Reflection.Emit. I guess once levi's ObjectFactory PR lands, we can revisit. Oh well 😞
There was a problem hiding this comment.
It's probably possible to do it like this:
internal interface ICachedActivator
{
object CreateInstance();
}
internal class CachedActivator<T> : ICachedActivator where T: class, new()
{
public object CreateInstance() => new T();
}... and then separately create a Dictionary<Type, ICachedActivator> where for each Type we construct an instance one time using reflection.
However I have absolutely no reason to think this would be faster than Activator.CreateInstance when running on an interpreter. It's probably slower. With the interpreter, the only difference between Activator.CreateInstance(typeof(T)) and new T() is having to look up the default constructor for T (assuming Activator.CreateInstance is an intrinsic), which most likely takes less time than finding typeof(T) in a dictionary keyed on that. I don't know how ObjectFactory is implemented but it's hard to see how it would be faster than Activator.CreateInstance on an interpreter.
There was a problem hiding this comment.
I think new T() uses Activator.CreateInstance under the covers: https://devblogs.microsoft.com/premier-developer/dissecting-the-new-constraint-in-c-a-perfect-example-of-a-leaky-abstraction/.
|
Pinging @dotnet/aspnet-blazor-eng for sign-off. |
pranavkm
left a comment
There was a problem hiding this comment.
Could you send an email over API-review? This API has precedence, since it's pretty close to how MVC's activator works. Outside of the few changes, this looks great.
| /// <inheritdoc /> | ||
| public IComponent CreateInstance(Type componentType) | ||
| { | ||
| var instance = Activator.CreateInstance(componentType); |
There was a problem hiding this comment.
I think new T() uses Activator.CreateInstance under the covers: https://devblogs.microsoft.com/premier-developer/dissecting-the-new-constraint-in-c-a-perfect-example-of-a-leaky-abstraction/.
|
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
|
@SteveSandersonMS With this PR merged I will finally be able to do what I wanted long time ago within my component library. I cannot thank you enough time for helping me. I really appreciate all your work. Thank you! |
|
@stsrki I am curious what you will use this feature for. @SteveSandersonMS will this feature be added to the 3.x versions of Blazor as well, or will it only be available in the .net 5 version? Either way I guess I need to figure out how to do multi targeting correctly with bUnit. |
|
It’s for 5.0 only. @stsrki Thanks for your help in making this happen too! |
|
@egil Basically in my components library Blazorise every component in the root project can be overriden and customized by any the supported frameworks(Bootstrap, Material, AntDesign, etc.) But since untll now I didn't have freedom to create the components, I had to come up with some workarounds. Like, whenever any component is created and rendered for the first time I would check if there exists custom implementation. In case it exists it would render that one instead. The problem was that I would basically create two components instead if just one. So with this PR I would be able to finally do that. |
|
@stsrki ahh I see. So for example, you have a public I wonder if the public |
|
@egil Yeah you got it. That's how it works. Well in theory it could be an interface but there is a lot more features and implementations behind the scenes. Just making it an interface would not suffice. |
|
@stsrki no I guess you have shared logic between them, so an interface might not be ideal. I was more wondering if it would be allowed by the Blazor compiler. |
|
@egil using plain C# you can render both abstract and interface types (when handling those by implementing a capable private static RenderFragment RenderAbstractComponent(int arg1) => builder =>
{
builder.OpenComponent<IJustTestComponent>(1);
builder.AddAttribute(2, nameof(IJustTestComponent.Arg1), arg1);
builder.CloseComponent();
};It's only the razor interpreter which starts acting stupid as soon as the component class is abstract or an interface: <JustTestComponentBase Arg1="123" />and lies on this with unnecessary false errors:
This is frustating and imho if the referenced type finally implements |
|
Hi @springy76. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context. |
This is an updated version of PR #19642 by @stsrki. Please see the original PR for context and earlier discussion.
Fixes #7962