2

I am struggling with what I believe is a covariance/contravariance problem with my design. I want return a generic object which is only known at run time.

I have the following classes/interfaces

public interface IBaseRepository
{
    int UserId { get; set; }

    // Retrieve
    SyncData GetRetrieveData();

    // Update
    SyncData GetUpdateData();
}

public interface IDomainRepository<T> : IBaseRepository where T : IDomainObject
{
    object GetValue(T domainObject, string id);
    void SetValue(T domainObject, string id, object value);

    // retrieve data 
    BatchResults<T> Retrieve();

    // update data
    BatchResults<T> Update(SynchroniseList synchroniseList);
}

I have some implementations of these:

public abstract class BaseRepository : IBaseRepository
{
    public int UserId { get; set; }

    public virtual SyncData GetRetrieveData()
    {
        return new SyncData();
    }

    public virtual SyncData GetUpdateData()
    {
        return new SyncData();
    }
}

public MyTaskRepository : BaseRepository, IDomainRepository<MyTask>
{
    public object GetValue(MyTask domainObject, string id)
    {
        return domainObject.GetValue();
    }

    void SetValue(MyTask domainObject, string id, object value)
    {
        domainObject.SetValue();
    }

    // retrieve data 
    public BatchResults<MyTask> Retrieve()
    {
        // do stuff specific to MyTask
        return new BatchResults<MyTask>();
    }

    // update data
    BatchResults<T> Update(SynchroniseList synchroniseList)
    {
        // do stuff specific to MyTask
        return new BatchResults<MyTask>();
    }
}

public MyOtherTaskRepository : BaseRepository, IDomainRepository<MyOtherTask>
{
    ...
}

The problem I am having is when using this repository. In a form I have

IBaseRepository repo = RepositoryFactory.Create(some parameters);

This returns a IDomainRepository which allows my to get/set retrieve/update data.

However, I dont know how to call Retrieve/Update as I cant cast to IDomainRepository because I dont know what domain object I will be working with.

I have been reading up on covariance/contravariance as I am thinking it has something to do with that However, I also have the feeling that my design is wrong in the sense I have made this overly complicated. I believe I could implement this in say c# 2.0 so I think I shouldnt event be concerned about covariance/contravariance.

Is it my design or do I need to sort out my in/out interfaces?

davros
  • 103
  • 1
  • 6

1 Answers1

0

Change the factory to return IDomainRepository<T>, as a commenter suggested. Otherwise use the as operator to typecast the interface pointer:

IBaseRepository repo = RepositoryFactory.Create(...);
IDomainRepository<MyTask> domainRepo = repo as IDomainRepository<MyTask>;
if (domainRepo != nil)
{
    // domainRepo implements IDomainRepository<MyTask>.
}

But testing the object to identify its type doesn't encourage polymorphic behaviour.

See also Test if object implements interface.

Community
  • 1
  • 1
groverboy
  • 1,133
  • 8
  • 20