源生成器:如何防止在 C# 中声明为“部分”的基类的实例化?

Jul*_*ian 0 c# abstract-class partial-classes sourcegenerators

概括

我有一个继承自抽象类的基类,但它本身必须声明为partial,因为我正在使用源生成器来生成部分实现。

如何防止partial class在 C# 中实例化它?有没有办法在编译时做到这一点?

编辑:我将 C# 8.0 (.NET Standard 2.1) 与 Xamarin.Forms 项目一起使用。

我试过了partial abstract,但是这是不允许的。

长话短说

在我的一个项目中,我一直使用一个abstract class作为ViewModel 的基类来实现MVVM 模式。以前,所述基类实现了该INotifyPropertyChanged接口,但现在我切换到CommunityToolkit.Mvvm,以便能够使用MVVM 源生成器 (我已经在其他项目中广泛使用了它,我什至写了一个关于它们的博客系列) 。

显然,在 C# 中,一个类只能是其中之一partialabstract但不能同时是两者,这是有道理的。由于源生成器仅与类一起使用partial,因此我的基类不能abstract再这样了。但是,这会产生一个问题,即我无法阻止基类在编译时实例化。虽然它仍然是一个abstract class,但无法实例化,但现在可以这样做。

抽象基类

这就是基类过去的样子(简化/修改的示例)

public abstract class ViewModelBase : INotifyPropertyChanged
{
    private bool _myBool;
    public bool MyBool
    {
        get => _myBool;
        set => SetField(ref _myBool, value);
    }

    private ICommand _myCommand;
    public ICommand MyCommand => _myCommand ??= new Command(MyMethod);

    private void MyMethod()
    {
        // ...
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

部分基类

更改后的基类现在如下所示:

public partial class ViewModelBase : ObservableObject
{
    [ObservableProperty]
    private bool _myBool;

    [RelayCommand]
    private void MyMethod()
    {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,它要小得多,但现在它可以被实例化,这是我想阻止的事情。

Gur*_*ron 5

您可以将部分类声明为抽象,但请注意关键字的顺序很重要(否则它将无法编译):

public abstract partial class ViewModelBase : ObservableObject
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

根据规范abstract- 、等修饰符sealed应位于partial关键字之前。