Search code examples
c#interfaceabstract-class

How can you restrict a method parameter based on an enum?


I feel like this is an anti pattern of some sort, but basically I've got 2 versions of the same type of repo that have the same type of properties and methods. I played with the idea of both an interface and an abstract class but in neither case can I get around what appears to be unnecessary checks. Here's the premise (using abstract class):

public abstract class BaseRepository
{
    public abstract RepositoryType RepositoryType { get; } //enum of File or DataBase
    public abstract CreateResult CreateItem (Item item);
    public abstract DeleteResult DeleteItemById(Guid Id);
    public abstract Item GetItem(Guid Id);
}

public class Item
{
    public Guid Id { get; }
    public string Name { get; }
    public ItemType ItemType { get; } //enum of File or DataRecord
    
    //other props...
}

public FileRepository : BaseRepository
{
    public override RepositoryType RepositoryType => RepositoryType.File
    
    public override CreateResult CreateItem(Item item)
    {
        if(item.ItemType != ItemType.File) throw InvalidOperationException("some error message") //problem is here

        //some logic.
    }

    //other overrides....
}

So there's a basic contract created for a repository via the BaseRepository, which is overridden by the FileRepository. An item basically has the same stuff whether it's a File item or a DataRecord item (there could arguably be an IItem interface and then 2 separate Items of DataRecord and File rather than an enum but that still doesn't solve the problem).

The problem is I don't see how I can pass in an Item with only ItemType File to the FileRepository. It feels like there should be a way of making sure that the FileRepository only receives items of type File and that a check shouldn't have to be made to ensure it's got the right type. How can I do this?


Solution

  • Make the repository generic, and introduce types for each type of item. eg:

    public abstract class Item
    {
    
    }
    public class FileItem : Item
    {
    
    }
    public abstract class Repository<TItem> where TItem : Item
    {
        public virtual string RepositoryType => typeof(TItem).Name;
        public abstract CreateResult CreateItem(TItem item);
        public abstract DeleteResult DeleteItemById(Guid Id);
        public abstract Item GetItem(Guid Id);
    }
    
    public class FileRepository : Repository<FileItem>
    {
        public override CreateResult CreateItem(FileItem item)
        {
            throw new NotImplementedException();
        }
    
        public override DeleteResult DeleteItemById(Guid Id)
        {
            throw new NotImplementedException();
        }
    
        public override Item GetItem(Guid Id)
        {
            throw new NotImplementedException();
        }
    }