-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[net10.0] Trimmable view handlers #28357
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
[net10.0] Trimmable view handlers #28357
Conversation
|
|
||
| internal interface IRemappable | ||
| { | ||
| void RemapForControls(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, i see i used static ctors which are random in AOT, so pretend I did something else in that bit of code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to use static abstract methods, but I struggled to get that working with netstandard. I think I would have to completely remove the Remap methods in netstandard which seems weird. Do we have some precedent for that already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Netstandard is not supported. We just use it to access type information in controls. And I am pretty sure that is not being used. Just for vs as well.
We are using static interface members and default interface members already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I ran into the problem that the static abstract methods can only be called via constrained generic type. This means we would need to have two different attributes for handlers:
[RemappableElementHandler<CheckBoxHandler>]
class CheckBox;
[ElementHandler<ProgressBarHandler>]
class ProgressBar;If we kept this as a simple interface with an instance method, we can use pattern matching in RemappingHelper to see if the handler implements IRemappable or not.
Alternatively, we could put the remapping logic into the static constructor of the handler. That would be likely more efficient, but we would have even less control over the order in which the remappings are applied. If I understand it correctly, the order of remapping matters and it is not desirable to remap a base type after the subclass because it could shadow the more specialized remappings.
We could maybe just do something like this:
class VisualElement
{
static VisualElement() => RemapForControls();
internal new static void RemapForControls()
{
// make sure we don't override any previously registered remappings of other derived classes
if (!RemappingHelper.ShouldRemap(typeof(VisualElement))
return;
Element.RemapForControls();
// ... do what VisualElement needs to do
}
class CheckBox
{
static CheckBox() => RemapForControls();
internal new static void RemapForControls()
{
if (!RemappingHelper.ShouldRemap(typeof(CheckBox))
remap;
VisualElement.RemapForControls(); // the base ctor will run on its own, but there is no guarantee that the base cctor runs BEFORE the derived class cctor. to achieve the right ordering, we need to call the base remapping ourselves
// ... do what CheckBox needs to do
}
}
class Label
{
static Label() => RemapForControls();
internal new static void RemapForControls()
{
if (!RemappingHelper.ShouldRemap(typeof(Label))
return;
VisualElement.RemapForControls();
// ... do the label remapping
}
}It would be less lazy than what is in this PR, but it wouldn't be any worse than today. It would still be trimmable and it would require one less interface.
(I will need to work on the thread-safety aspect of the code. I don't think the code with the early returns is actually correct.)
| public override IElementHandler CreateHandler() | ||
| { | ||
| var handler = new THandler(); | ||
| RemappingHelper.RemapIfNeeded(typeof(THandler), handler); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized this doesn't work. It's the element that can be remapped, not the handler. I need to figure out how to address this without having to change the API drastically. The cctors approach might be the best after all.
|
/rebase |
52a5cff to
2cdf173
Compare
|
@jfversluis and @StephaneDelcroix and FYI and source generators and thoughts? |
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using System.Reflection; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like a red flag for trimming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I remember correctly, this is necessary to use this extension method, which is trimming and AOT-friendly:
viewType.GetCustomAttribute<ElementHandlerAttribute>()
This PR supersedes #28115
Description of Change
This proof of concept explores how we could get rid of the long DI setup code in AppHostBuilderExtensions:
Listing all the classes this way makes it impossible for the trimmer to remove any of them.
The idea in this PR is to connect the element and the element handler using an attribute instead of looking up the handler in the DI container:
EDIT: The
IRemappableinterface used in earlier iteration has been removed.if the control isn't used anywhere in the app, the trimmer will remove the element type. When the type is removed, the handler type is removed as well, because the only link to the handler type is the custom class attribute.
The DI mechanism is still checked first before looking for the attribute for two reasons:
Notes:
Feedback is very welcome!
Fixes
/cc @jonathanpeppers @PureWeen @mattleibow @ivanpovazan