Ryan Vice
Ryan Vice

Reputation: 2181

Explicit cast to T on generic method required in some cases

I have a situation that is confusing me and was hoping for some help. In the code below the FindById method works without having to cast the return but the UpdatedAuditedEntity call doesn't. Note that:

  1. AuditedEntity derives from Entity
  2. Casting auditedEntity to an Entity doesn't work, only casting to T works.

Any insight into what I'm missing here would be greatly appreciated. At first I thought it had to do with variance but as I mentioned above I tried down casting with no sucess.

    public class NHibernateRepository<T> : NHibernateBase,
    IRepository<T> where T : Entity
{

    public IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate)
    {
        var query = GetQuery(predicate);
        return Transact(() => query.ToList());
    }

    public T FindById(int id)
    {
        // TODO: Why does this work when below doesn't
        return FindAll(e => e.Id == id).FirstOrDefault();
    }

    private T UpdateAuditedEntity(T item)
    {
        var auditedEntity = item as AuditedEntity;

        if (auditedEntity == null) return item;

        auditedEntity.DateModified = DateTime.UtcNow;

        // TODO: figure out why this cast is necessary
        return auditedEntity as T;
    }

Upvotes: 1

Views: 104

Answers (2)

AakashM
AakashM

Reputation: 63338

AuditedEntity derives from Entity

OK, but in this generic class, T is of an arbitrary derivative of Entity. The compiler doesn't care that your auditedEntity was created by casting item - indeed, there could be custom conversions at play here doing unexpected things - so doesn't allow you to return a variable typed as AuditedEntity from a method that asks for a T.

In this particular method, since item and auditedEntity are the same object, you can just do

return item;

as the last statement of UpdateAuditedEntity and the compiler will be happy.

Upvotes: 2

Mark M
Mark M

Reputation: 976

This is necessary because although both AuditedEntity and T are derived from Entity, AuditedEntity may not inherit whatever type is represented by T.

For example, say you created a type "OtherEntity" that directly inherited Entity. An instance of NHibernateRepository<OtherEntity> would have UpdateAuditedEntity return an AuditedEntity, which does not inherit OtherEntity - so the returned type would not be valid.

Upvotes: 2

Related Questions