0

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 => _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;
    }
}

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.

8
  • Make it abstract - public abstract partial class ViewModelBase .... You can have partial abstract classes. Commented Apr 6, 2023 at 15:27
  • @GuruStron In which C# version? Commented Apr 6, 2023 at 15:28
  • In any which is more or less relevant nowadays, AFAIK. Commented Apr 6, 2023 at 15:29
  • 2
    oh, okay, I missed that. I tried partial abstract, but it didn't allow it. It seems that abstract partial works, however. I guess that answers it, then. Thanks Commented Apr 6, 2023 at 15:30
  • 3
    If you give the class a single constructor and make it protected, it cannot be directly instantiated (except by subclass instances), but sub-class instances can be instantiated. Commented Apr 6, 2023 at 16:31

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.