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.
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.
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;
}
}
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.
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.