[net10.0] Trimmable view handlers#28357
Conversation
|
|
||
| internal interface IRemappable | ||
| { | ||
| void RemapForControls(); |
There was a problem hiding this comment.
There was a problem hiding this comment.
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.
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.
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.
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.
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.
this looks like a red flag for trimming.
There was a problem hiding this comment.
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