繁体   English   中英

属性挂钩 MSBuild/Roslyn

[英]Attribute hooking MSBuild/Roslyn

如果我想创建一个与 .NET 构建过程挂钩并转换/转换标准 C# 自动属性的属性(派生自 System.Attribute),例如:

[Notify]
public string Name { get; set; }

到此代码,然后编译:

private string _nameField;
public string Name
{ 
     get => _nameField;
     set  
     {
         if (!EqualityComparer<string>.Default.Equals(_nameField, value))
         {
              _nameField = value;
              NotifyPropertyChanged(nameof(Name));
         }
     }
}

我将如何实现它? 我该怎么办? 如何让属性挂钩到构建中? 如您所见,我对构建过程和 Roslyn 都一无所知。 但我想摆脱多余的 MVVM 样板代码,不再花太多时间进行枯燥的重复输入......

谢谢,克里斯

为此有一个Fody编织器,称为PropertyChanged

Fody 是一个用于在编译过程结束时修改代码的系统。 PropertyChanged 编织器自动为实现INotifyPropertyChanged的所有类中的所有属性执行更改通知。 它有多种使用属性、实现方法等来控制生成的方法。

他们的 GitHub 项目页面中的示例如下所示:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }
    public string FullName => $"{GivenNames} {FamilyName}";
}

编织器解释上述内容并生成如下代码:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get => givenNames;
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged(InternalEventArgsCache.GivenNames);
                OnPropertyChanged(InternalEventArgsCache.FullName);
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get => familyName;
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged(InternalEventArgsCache.FamilyName);
                OnPropertyChanged(InternalEventArgsCache.FullName);
            }
        }
    }

    public string FullName => $"{GivenNames} {FamilyName}";

    protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
    {
        PropertyChanged?.Invoke(this, eventArgs);
    }
}

internal static class InternalEventArgsCache
{
    internal static PropertyChangedEventArgs FamilyName = new PropertyChangedEventArgs("FamilyName");
    internal static PropertyChangedEventArgs FullName = new PropertyChangedEventArgs("FullName");
    internal static PropertyChangedEventArgs GivenNames = new PropertyChangedEventArgs("GivenNames");
}

当然,您将无法访问该版本,因为它发生在编译过程结束时的某个地方,并且您的源不受影响。 调试代码可能有点困难。

为了帮助实现这一点,PropertyChanged 编织器会查找与各种规则匹配的预实现方法并生成代码来调用这些方法。 如果您在 class 中有OnPropertyChanged方法,它将调用该方法而不是生成样板版本。 或者,您可以在上面的 class 中添加一个OnFamilyNameChanged方法,该方法将在OnPropertyChanged方法之前调用。

您可以为此使用 Roslyn 源代码生成器: Source Generators Cookbook

有一个INotifyPropertyChanged示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM