在 C# 中对括号表达式进行赋值意味着什么?

Ale*_*kov 30 c# collection-initializer

我在阅读 Avalonia 源代码时发现了这句话:

return new MenuFlyoutPresenter
{
    [!ItemsControl.ItemsProperty] = this[!ItemsProperty],
    [!ItemsControl.ItemTemplateProperty] = this[!ItemTemplateProperty]
};
Run Code Online (Sandbox Code Playgroud)

我从未见过这样的语法。如果没有索引属性或 this[] 访问器,这些括号会做什么?如果它们引用的属性不是 bool,为什么它们会用感叹号否定?也许是某种空检查?

代码本身包含在以下 cs 文件中:

https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Controls/Flyouts/MenuFlyout.cs

我跟踪了代码,但无法理解该语法的作用。

can*_*on7 35

这里发生了一些事情。

首先,语法:

var menu = new MenuFlyoutPresenter
{
    [key] = value,
};
Run Code Online (Sandbox Code Playgroud)

是一个集合初始值设定项,是以下形式的简写:

var menu = new MenuFlyoutPresenter();
menu[key] = value;
Run Code Online (Sandbox Code Playgroud)

该索引器在这里定义为:

public IBinding this[IndexerDescriptor binding]
{
    get { return new IndexerBinding(this, binding.Property!, binding.Mode); }
    set { this.Bind(binding.Property!, value); }
}
Run Code Online (Sandbox Code Playgroud)

所以key存在一个IndexerDescriptor,并且value是一个IBinding

那么,这件事是怎么回事呢?

!ItemsControl.ItemsProperty
Run Code Online (Sandbox Code Playgroud)

我们可以从您的链接中看到这ItemsProperty是一个DirectProperty<TOwner, TValue>, 并且最终在此处!实现了运算符:

public static IndexerDescriptor operator !(AvaloniaProperty property)
{
    return new IndexerDescriptor
    {
        Priority = BindingPriority.LocalValue,
        Property = property,
    };
}
Run Code Online (Sandbox Code Playgroud)

Avalonia 似乎喜欢重载运算符,例如!~来做你可能意想不到的事情(通常会使用一个方法)。在本例中,他们使用!on anAvaloniaProperty作为访问该属性绑定的简写。


Mat*_*son 11

演示允许此语法的方法的相对简单的类是:

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();
}
Run Code Online (Sandbox Code Playgroud)

需要注意的一些事项:

  • Demo实现operator!允许!运算符用于该类型的值(例如初始化!ItemsProperty中的 SomeMethod())。
  • Demothis实现一个索引器,它允许在集合初始值设定项的右侧使用索引(通过)。
  • 索引器还允许[x] = y使用 中使用的集合初始化语法SomeMethod()

operator()!它是运算符与索引器的组合this[Demo],从而启用了该语法。