Muxa
Muxa

Reputation: 5643

Cast type in a generic method to a different one for inner generic method call

I've got this repository method:

    public virtual T Get<T>(object primaryKey) where T : IDalRecord, new() //note: can't change the where clause
    {
        return Record<T>.FetchByID(primaryKey); // how? <--compile time error
    }

defined in a 3-rd party assembly:

    public class Record<T> where T : Record<T>, IRecordBase, new()
    {
        public static Record<T> FetchByID(object primaryKey) { /*...*/ }
    }

My T and the 3-rd party T are not directly compatible, however my objects that inherit from Record<T> also also implement IDalRecord, so i can cast the object instance to any of these type.

But how can i tell the compiler to "cast" (IDalRecord)T to (Record<T>)T?

Upvotes: 4

Views: 197

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80754

There is no way to tell the compiler that T actually inherits from Record<T>. The reason is simple: because it is not true, generally speaking. Indeed, your Get method may, theoretically, be called with any argument, not necessarily that inheriting from Record<T>.

The fact that T does, in fact, inherit from Record<T> only becomes known at runtime, when your method is actually called. Therefore, necessary checks and constructs must take place at that same moment.

interface IHelper { object Fetch(object key); }

class Helper<T> : IHelper where T : Record<T>, IRecordBase, new()
{
    public object Fetch(object key) { return Record<T>.FetchByID(key); }
}

public virtual T Get<T>(object primaryKey) where T : IDalRecord, new()
{
    var helperType = typeof( Helper<> ).MakeGenericType( typeof( T ) );
      // This will throw an exception if T does not satisfy Helper's where clause

    var helper = Activator.CreateInstance( helperType ) as IHelper; 
    return (T) helper.Fetch(primaryKey);
}

Keep in mind that is it entirely possible (and even encouraged) to cache those Helper<T> objects for performance.

You can also just use old dumb reflection: find the method FetchByID by name and call it dynamically. But that would cause enormous performance penalty.

Upvotes: 5

Related Questions