Search code examples
c#interfacereturn-typeinterface-implementation

Return types not matching


I have this method that expects MoreOptionsPopupResult as a return. deleteAttachmentModalViewModel.result is of type MoreOptionsPopupResult, however do I get an error when compiling saying this:

Error CS0738 'PopupProvider' does not implement interface member 'IPopupProvider.ShowDeleteAttachmentPopup()'. 'PopupProvider.ShowDeleteAttachmentPopup()' cannot implement 'IPopupProvider.ShowDeleteAttachmentPopup()' because it does not have the matching return type of 'Task<MoreOptionsPopupResult>'.

In my understanding are both types the same so I am confused why it brings this error.

This is MoreOptionsPopupResult:

namespace SiRiAs.Lib.Helpers {
    public enum MoreOptionsPopupResult {
        Delete,
        Update,
        Export
    }
}

This is where I get the error message:

public async Task<MoreOptionsPopupResult?> ShowDeleteAttachmentPopup() {
    var scope = _serviceProvider.CreateScope();
    var deleteAttachmentModalViewModel = scope.ServiceProvider.GetService<DeleteAttachmentModalViewModel>();
    var deleteAttachmentPopup = new DeleteAttachmentModal(deleteAttachmentModalViewModel);
    var asyncEventAwaiter = new AsyncEventAwaiter<NavigatedToEventArgs>();

    App.Current.MainPage.NavigatedTo += asyncEventAwaiter.EventListener;

    await App.Current.MainPage.Navigation.PushModalAsync(deleteAttachmentPopup);

    await asyncEventAwaiter.Wait();

    App.Current.MainPage.NavigatedTo -= asyncEventAwaiter.EventListener;

    return (MoreOptionsPopupResult?)deleteAttachmentModalViewModel.result;
}

And this is where result is implemented:

public partial class DeleteAttachmentModalViewModel : ObservableObject {
    private readonly IUnitOfWork _unitOfWork;
    private readonly IPopupProvider _popupProvider;
    
    public MoreOptionsPopupResult result;
    
    public DeleteAttachmentModalViewModel(IUnitOfWork unitOfWork, IPopupProvider popupProvider) {
        _unitOfWork = unitOfWork;
        _popupProvider = popupProvider;
    }
    
    [ICommand]
    public void DeleteButtonPressed() {
        result = MoreOptionsPopupResult.Delete;
    }

This method works just fine:

public async Task<MoreOptionsPopupResult?> ShowMoreOptionsPopup() {
    var popup = new MoreOptionsPopup();
    var result = await Shell.Current.CurrentPage.ShowPopupAsync(popup);
    return (MoreOptionsPopupResult?)result;
}

Does anyone can think of why the one method works just fine and the other one doesn't like the return type? It seems like they should be the same.


Solution

  • A nullable enum (ie Nullable<MoreOptionsPopupResult>) is an entirely different type than its corresponding non-nullable enum.

    This means that Task<MoreOptionsPopupResult> and Task<MoreOptionsPopupResult?> are completely different, as the compiler is telling you.

    Take this stripped down version of your code:

    public interface IPopupProvider
    {
        Task<MoreOptionsPopupResult> ShowDeleteAttachmentPopup();
    }
    
    public class PopupProvider : IPopupProvider
    {
        public async Task<MoreOptionsPopupResult?> ShowDeleteAttachmentPopup()
        {
            throw new NotImplementedException();
        }
    }
    
    public enum MoreOptionsPopupResult
    {
        Delete,
        Update,
        Export
    }
    

    This has the same compile-time error you're getting. However, if you remove the ? from the ShowDeleteAttachmentPopup method in the PopupProvider class, it will compile correctly.

    public async Task<MoreOptionsPopupResult> ShowDeleteAttachmentPopup()
    

    Or, if you want to allow the method to return a nullable enum value, you'll need to modify the interface method's return type.