Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / March 2008

Tip: Looking for answers? Try searching our database.

Generics Question - how to implement a method on a generic that     returns the same type as the generic

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
IUnknown - 20 Mar 2008 19:34 GMT
I am having a really bad time with this one. For some reason, I can't
seem to remember how to implement this (elegantly) in c# ... so I
thought I would ask the community.

Basically, I have defined a generic.... and I want to expose a virtual
method on the generic that returns the same generic.

... ignoring the obvious stupidity below, what I am missing that would
allow for something like this? I am purposefully dumbing down my
example for the sake of brevity....

Also, the actual goal/purpose of the code isn't the issue here, it is
more of a language feature question. The example code below is just
that...... example code.

    public class TestGeneric<T>
    {
        List<T> _mylist = new List<T>;

        public virtual TestGeneric<T> CutInHalf()
        {
             // cut the list in half and return it to the caller
        }

        public virtual Add(T item)
        {
         _mylist.Add(item);
        }

    }

    public class TestClass
    {
        public string myGUID = System.Guid.NewGuid().ToString();
    }

    public class  TestClassHeap : TestGeneric<TestClass>
    {
    }

.... all the code above will compile nicely... now if I actually try
to use it somewhere, i will get type mismatch issues...

    TestClassHeap heap = new TestClassHeap();
    heap.Add(new TestClass());
    heap.Add(new TestClass());

    // this line fails to compile because the type returned by
TestGeneric::CutInHalf is different
    // than the actual defined type TestClassHeap... which is a
perfectly reasonable interpretation
    // by the compiler.
    TestClassHeap half = heap.CutInHalf();

What I was hoping to do is return from a method on the generic, and
instance of the DERIVED type (as shown in the usage example above).

I can 'hack it' and get it to work by doing this (ignore the syntactic
issues please, i am doing this on-the-fly... )

               public class TestGeneric<T, CT> where CT: new()
    {
        List<T> _mylist = new List<T>;

        public virtual CT CutInHalf()
        {
             // cut the list in half and return it to the caller
        }

        public virtual Add(T item)
        {
         _mylist.Add(item);
        }

    }

    public class TestClass
    {
        public string myGUID = System.Guid.NewGuid().ToString();
    }

    public class  TestClassHeap : TestGeneric<TestClass, TestClassHeap>
    {
    }

The definition above does what I want, but it is somewhat hackish, as
it requires me to pass in the class i am defining as a generic
parameter to the generic that the defined class is deriving from ...

Like I said, the hack works, but I was hoping for a more elegant
solution.... and my brain is deadlocked.

:)

Thanks in advance!
Peter Duniho - 20 Mar 2008 20:10 GMT
> [...]
>      // this line fails to compile because the type returned by
[quoted text clipped - 10 lines]
> Like I said, the hack works, but I was hoping for a more elegant
> solution.... and my brain is deadlocked.

I guess that depends on your definition of "elegant".  :)

The basic issue here is that the generic class, used as a base class in  
your example, is only able to create a class instance it knows about.  As  
you saw, if you tell it about the derived class, all is fine.  But  
otherwise, it can only return an instance of itself, which of course is  
not assignable or even castable to the derived class.

One solution would be to take advantage of the fact that the method is  
virtual, and reimplement it in your derived class.  In that class  
obviously you would know to return the derived class:

    class TestClassHeap : TestGeneric<TestClass>
    {
        public override TestGeneric<TestClass> CutInHalf()
        {
           // etc.
        }
    }

You could either reimplement the method entirely, or you could call the  
base class and have it do whatever it normally would do, then take the  
results and convert them into the derived class.  The former is IMHO less  
maintainable but would be more efficient.  The latter is going to wind up  
creating an instance of TestGeneric<TestClass> that you don't actually  
return, but rather copy (if you can) members into an instance of  
TestClassHeap for use there, and in doing so taking advantage of the base  
implementation.  There's extra overhead, but it means that you don't have  
to copy and paste logic.

If you have members that are private to the base class, then you'll need  
to provide some sort of protected helper method that can be called from a  
derived class to handle the copying for you.

Another solution might involve reflection, but that's potentially going to  
be a noticeable performance problem and I'm not convinced that you'd save  
enough performance-wise by avoiding creating the base class instance to  
justify the cost of reflection.

In the end, I'm left thinking that what you've already come up with is a  
"reasonably" elegant solution.  I mean, I would agree if you felt that  
making the derived class a type parameter for the generic class is kind of  
awkward.  But it's not like the other possible solutions don't have their  
own awkward aspects either.

One possible improvement might be to make the method itself generic.  That  
way only callers to the method need to specify the type:

    class TestGeneric<T>
    {
        public virtual U CutInHalf<U>() where U : new()
        {
            // etc.
        }
    }

Then you call it:

    TestClassHeap half = heap.CutInHalf<TestClassHeap>();

I hope that helps.  :)

Pete

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.