I'm reading Avalonia source code and I came across this sentence:
return new MenuFlyoutPresenter
{
[!ItemsControl.ItemsProperty] = this[!ItemsProperty],
[!ItemsControl.ItemTemplateProperty] = this[!ItemTemplateProperty]
};
I've never seen a syntax like that. What does those bracket do if there is no indexed property or this[] accessor?, and why are they negated with the exclamation mark if the property they are referring to is not a bool?, maybe some kind of null-check?
The code itself is contained in the following cs file:
https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Controls/Flyouts/MenuFlyout.cs
I've tracked the code but I was unable to understand what that syntax does.
There are a couple of things going on here.
First, the syntax:
var menu = new MenuFlyoutPresenter
{
[key] = value,
};
Is a collection initializer , and is shorthand for:
var menu = new MenuFlyoutPresenter();
menu[key] = value;
That indexer is defined here as:
public IBinding this[IndexerDescriptor binding]
{
get { return new IndexerBinding(this, binding.Property!, binding.Mode); }
set { this.Bind(binding.Property!, value); }
}
So the key
there is an IndexerDescriptor
, and the value
is an IBinding
.
So, what's going on with this thing?
!ItemsControl.ItemsProperty
We can see from your link that ItemsProperty
is a DirectProperty<TOwner, TValue>
, and that ultimately implements the !
operator here :
public static IndexerDescriptor operator !(AvaloniaProperty property)
{
return new IndexerDescriptor
{
Priority = BindingPriority.LocalValue,
Property = property,
};
}
Avalonia seems to like overloading operators such as !
and ~
to do things you might not expect (and would normally use a method for). In this case, they use !
on an AvaloniaProperty
as a shorthand for accessing that property's binding.
A relatively simple class that demonstrates a way of allowing this syntax is:
public sealed class Demo
{
public Demo this[Demo index] // Indexer
{
get => !index;
set {} // Not needed to demonstrate syntax.
}
public static Demo operator !(Demo item) => item;
public Demo ItemsProperty => _empty;
public Demo ItemTemplateProperty => _empty;
public Demo SomeMethod(Demo ItemsControl)
{
return new Demo
{
[!ItemsControl.ItemsProperty] = this[!ItemsProperty],
[!ItemsControl.ItemTemplateProperty] = this[!ItemTemplateProperty],
};
}
static Demo _empty = new();
}
Some things to note:
Demo
implements operator!
which allows the !
operator to be used on values of that type (eg the !ItemsProperty
in the SomeMethod()
initialisation).Demo
implements an indexer which is what allows the use of the indexing (via this
) on the right-hand side of the collection initialiser. [x] = y
collection initialisation syntax used in SomeMethod()
. It's the combination of the operator()!
operator along with the this[Demo]
indexer that enables the syntax.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.