如何防止在C#中声明为“partial”的基类的实例化?

huangapple go评论73阅读模式
英文:

Source Generators: How can I prevent the instantiation of a base class declared as "partial" in C#?

问题

摘要

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

如何在 C# 中防止实例化这个 partial class?是否有一种方法可以在编译时实现这一点?

**编辑:**我正在使用 C# 8.0(.NET Standard 2.1)与一个 Xamarin.Forms 项目。

我尝试了 partial abstract,但不被允许。

简短摘要

在我的一个项目中,我一直在使用一个作为 ViewModels 基类的 abstract class 来实现 MVVM 模式。以前,这个基类实现了 INotifyPropertyChanged 接口,但现在我正在切换到 CommunityToolkit.Mvvm 以便能够使用 MVVM Source Generators (我在其他项目中已广泛使用它们,甚至写了一个博客系列介绍它们)

显然,在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;
    }
}

部分基类

现在更改后的基类如下:

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

    [RelayCommand]
    private void MyMethod()
    {
        // ...
    }
}

如预期的那样,它更小了,但现在它可以被实例化,我希望能防止这种情况发生。

英文:

Summary

I have a base class which inherits from an abstract class, but must itself be declared as partial, because I'm using Source Generators to generate parts of the implementation.

How can I prevent the instantiation of that partial class in C#? Is there some way to do this at compile-time?

Edit: I'm using C# 8.0 (.NET Standard 2.1) with a Xamarin.Forms project.

I've tried partial abstract, but that isn't allowed.

TL;DR

In one of my projects, I have been using an abstract class that serves as a base class for ViewModels to implement the MVVM pattern. Previously, said base class implemented the INotifyPropertyChanged interface, but now I am switching to the CommunityToolkit.Mvvm in order to be able to use the MVVM Source Generators (which I have used in other projects extensively already, I even wrote a blog series about them).

Apparently, in C#, a class can only be either partial or abstract but not both at the same time, which makes sense. Since the Source Generators work with partial classes only, my base class cannot be abstract anymore. However, this creates the problem that I cannot prevent the base class from being instantiated at compile-time. While it was still an abstract class, it couldn't be instantiated, but now it's possible to do so.

Abstract base class

This is what the base class used to look like (reduced/modified example):

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

    private ICommand _myCommand;
    public ICommand MyCommand =&gt; _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&lt;T&gt;(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer&lt;T&gt;.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

Partial base class

The changed base class looks like this now:

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

    [RelayCommand]
    private void MyMethod()
    {
        // ...
    }
}

It's much smaller, as expected, but now it can be instantiated, which is something I would like to prevent.

答案1

得分: 5

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

public abstract partial class ViewModelBase : ObservableObject
{
    // ...
}

根据规范,修饰符如abstractsealed等应在partial关键词之前。

英文:

You can declare partial classes as abstract, but note that order of keywords is important (otherwise it will not compile):

public abstract partial class ViewModelBase : ObservableObject
{
    // ...
}

As per spec - modifiers like abstract, sealed, etc should precede the partial keyword.

huangapple
  • 本文由 发表于 2023年4月6日 23:22:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75951187.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定