简体   繁体   中英

Cast a concrete class instance to an interface that uses generics

Here is my concrete Repository that derives from an abstract base class

public class DepartmentRepository : RepositoryBase<Department>, IDepartmentRepository

public abstract class RepositoryBase<T> : IRepository<T> where T : class, IPersistantBusinessObject

Here is my interfaces

public interface IDepartmentRepository : IRepository<Department>

public interface IRepository<T> where T : IPersistantBusinessObject

public interface IPersistantBusinessObject { ... }

And here is my entities

public class Department : BusinessObjectBase

public abstract class BusinessObjectBase : IPersistantBusinessObject

How do I cast my DepartmentRepository to the generic IRepository?

DepartmentRepository rep = new DepartmentRepository();
(IRepository<IPersistentBusinessObject>)rep; // this doesn't work

Ideas? In case you're wondering, this is an asp.net MVC3 application using the repository pattern. Did I over architect the interfaces? How am I suppose to use a generic repository now?

Thanks.

EDIT: Here is my IRepository interface. As asked about why I need to cast to IRepository, it is actually only so I can use the "SaveChanges" method, because I want to intercept any exceptions from the database and handled in a common way.

public interface IRepository<T> where T: IPersistantBusinessObject
{
    IQueryable<T> Retrieve();
    T Retrieve(int id);
    IQueryable<T> RetrieveActiveAndInActive();
    T RetrieveActiveAndInActive(int id);
    void Add(T domainObject);
    void SaveChanges();
    void Delete(T domainObject);
    void Delete(int id)
 }

What are you trying to do here? I can't think of a situation in which you would want to cast to IRepository<IPersistentBusinessObject> . What code is dependent on what abstraction?

I would usually expect other code to depend on the abstraction of IDepartmentRepository , and can't really see the use case for IRepository<T> or even IPersistentBusinessObject at all. Again, if you can find a use case for code that depends on that abstraction, then they are valuable; otherwise, YAGNI .

(By the way, this is one reason why test-driven development is valuable. You can figure out which abstractions you need by writing unit tests, and seeing what classes need to be mocked to isolate testing of certain functionality, instead of just vaguely abstracting everything into interfaces because you were told they were better than concrete types. Start with concrete types, and when your tests force you to extract an interface, that's the right time!)


Really though, this is a question of covariance of generic types . It should work if you say

public interface IRepository<out T> where T : IPersistantBusinessObject

You need to cast it to IRepository<Department> .

DepartmentRepository derives from RepositoryBase<Department> which implements IRepository<Department> .

You might want to have a look at co and contravariance ...

As Daniel implies, you can't cast it to IRepository, because you've defined the IRepository interface to only exist in conjunction with another type T. So "IRepository" as an interface does not exist.

If you want to be able to use an interface "IRepository" then it needs to be a standalone interface without the type dependence.

Perhaps you need two interfaces, one which implements the basic functionality you want in IRepository, and one which implements the generic methods for type T. eg

<!-- language: lang-c# -->
public interface IRepository
{
  SaveChanges()
...
}

public interface IRepositoryFor<T> where T : IPersistantBusinessObject
{
  T GetFirst(); // or whatever
...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM