Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return concrete type in abstract class

We have an abstract class BaseClass (note generic arg!) with a method called me. Me returns this.

If we use Me in the concrete classes we will get a return type object. Then we have to cast the result of Me to the type we originally are working with.

How can we achieve that Me returns the actual type of this? In this example type A?

public abstract class BaseClass<TIdentifier>{
 public virtual object Me{ get { return this; } }
}

public class A: BaseClass<long>
{

}

public class B: BaseClass<long>
{

}

public class controller{
   public void SomeMethod(){
       var a = new A();
       var b = new B();

       var aObject = a.Me; // this will be of type object
       var aObjectCasted = (A)aObject; // cast to original

       // How I want it
       var aConcrete = a.Me; // this returns type a
   }
}

Update

Since some people really, desperately (wink:-)) wish to understand what I'm actually trying to do.

With NHibernate we are doing this:

var result = Session.Get<A>(idToLookUp);

In some cases it happens that result isn't of type A but is of type AProxy, due to laze loading etc. Now if we want to cast result to something else: we will get an invalidcastexception because the actual type of result isn't A but AProxy. And that type can't be casted. We can only cast type A to the other type.

A workaround for this is described here: http://sessionfactory.blogspot.be/2010/08/hacking-lazy-loaded-inheritance.html. That's where the Me property in the above examples comes in.

So to get result of type A and not of type AProxy we now have to do this:

var result = (A)Session.Get<A>(idToLookUp).Me;

Note we have to cast me back to type A if we want to get to read and know the property of result.

My question: can we get rid of the casting and adjust the Me property so we instantly return the concrete type?

Hope it's clear now.

like image 744
Tom B. Avatar asked Jan 28 '16 11:01

Tom B.


1 Answers

You could use an interface on your derived classes:

public interface IStrongTypedMe<T>
{
    T Me();
}

Your derived classes would become:

public class A: BaseClass<long>, IStrongTypedMe<A>
{
    public new A Me()
    {
        return base.Me() as A;
    }
}

This is assuming you can change A, of course.

Update:

I understand the issue now (only had time to read the linked article now).

Try using an extension method to do the casting for you like this:

    public static TReturnType As<TReturnType,TIdentifier>(this BaseClass<TIdentifier> proxyObject)
        where TReturnType : class
    {
        return proxyObject.Me as TReturnType;
    }

And you'd use it like:

var result = Session.Get<A>(idToLookUp).As<A,long>();

No changes to A or B required.

like image 101
toadflakz Avatar answered Oct 19 '22 23:10

toadflakz