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 (e.g. 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.