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# / January 2008

Tip: Looking for answers? Try searching our database.

Can a base class method return an object of an inherited class typ

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Ethan Strauss - 09 Jan 2008 20:39 GMT
Hi,

I have a class which "BiologySequence" which looks about like this.

  public class BiologySequence
   {
       private string _Sequence;

    public string Sequence
{
get
{
return _Sequence;
}
set
{
_Sequence = value;
}
}

       public BiologySequence(string sequence)
       {
           if (sequence != null)
           {
               _Sequence = sequence;
           }
           else
           {
               _Sequence = string.Empty;
           }
       }
}

and an inherited class (NucleicAcidSequence) which has no other properties
important for this question.

I want to have the base class have a "Subsquence" method which is
essentially the same as the substring method of string. I have written

       public BiologySequence Subsequence(int firstBase, int lastBase)
       {
           BiologySequence ToReturn = this.MemberwiseClone();
           ToReturn.Sequence = _Sequence.Substring(firstBase, lastBase -
firstBase);
           return (ToReturn);
       }
which, I think works, but it always returns an object of type
BiologySequence regardless of what actual class it is called from.

I have tried all sorts of things to recast the object to be returned as the
same type as the calling type, but I can't find one which works.
Is there a way to do this, or do I need to explicitly write this method for
each inheriting class?

Thanks!
Ethan

Ethan Strauss Ph.D.
Bioinformatics Scientist
Promega Corporation
2800 Woods Hollow Rd.
Madison, WI 53711
608-274-4330
800-356-9526
ethan.strauss@promega.com
Nicholas Paldino [.NET/C# MVP] - 09 Jan 2008 21:00 GMT
Ethan,

   Given the limitations of the constraint system (you won't be able to
call the constructor of the NucleicAcidSequence, since the only constructor
you can create a constraint against is the default parameterless one), you
should probably make a parameterless constructor, and then make your
Subsequence method generic:

public T Subsequence<T>(int firstBase, int lastBase) where T :
BiologySequence, new()
{
   // Create the return value.
   T retVal = new T();

   // Assign the new sequence.
   retVal.Sequence = Sequence.Substring(firstBase, lastBase - firstBase);

   // Return.
   return retVal;
}

   Of course, it means that anything that derives from BiologySequence must
have a default parameterless constructor if they want to use the Subsequence
method.  If you have other properties, they have to be copied over as well.
The problem here is that if you have a large hierarchy chain, then you will
have to have a lot of case statements which will copy all the applicable
properties, or use reflection, which is probably not the direction you
wanted to head in the first place.

Signature

         - Nicholas Paldino [.NET/C# MVP]
         - mvp@spam.guard.caspershouse.com

> Hi,
>
[quoted text clipped - 63 lines]
> 800-356-9526
> ethan.strauss@promega.com
Peter Duniho - 09 Jan 2008 21:10 GMT
> [...]
> I want to have the base class have a "Subsquence" method which is
[quoted text clipped - 16 lines]
> for
> each inheriting class?

Can you provide a complete-but-concise example of code that is written as  
you'd like it to work, but which doesn't?

The Object.MemberwiseClone() method will return the same type as the  
instance being used.  So the code you've posted should do exactly what it  
_seems_ like to me that you want to do.  If your instance is actually a  
NucleicAcidSequence, then calling MemberwiseClone() on that instance  
should return you a NucleicAcidSequence, even when called from a method in  
BiologySequence.

The method will return a reference typed as BiologySequence, but the  
caller should be able to cast to NucleicAcidSequence without any trouble.

Here's a simple program that demonstrates this working:

using System;
using System.Collections.Generic;
using System.Text;

namespace TestCloneBaseClass
{
    class Program
    {
        class A : ICloneable
        {
            #region ICloneable Members

            public object Clone()
            {
                return this.MemberwiseClone();
            }

            #endregion
        }

        class B : A
        {
        }

        static void Main(string[] args)
        {
            A a = new B();
            B b = (B)a.Clone();

            Console.WriteLine("Type of b: " + b.GetType().Name);
            Console.ReadLine();
        }
    }
}
Ethan Strauss - 09 Jan 2008 21:46 GMT
Thanks Peter.
I can't get it to compile.
I get "Cannot implicitly convert type 'object' to
'BiologyTools.BiologySequence'. An explicit conversion exists (are you
missing a cast?)" on the line which contains MemberwiseClone.

Ethan

> > [...]
> > I want to have the base class have a "Subsquence" method which is
[quoted text clipped - 66 lines]
>      }
> }
Peter Duniho - 09 Jan 2008 23:39 GMT
> Thanks Peter.
> I can't get it to compile.
> I get "Cannot implicitly convert type 'object' to
> 'BiologyTools.BiologySequence'. An explicit conversion exists (are you
> missing a cast?)" on the line which contains MemberwiseClone.

Well, you could look at the sample I posted for reference.

The error is telling you exactly what's wrong.  The compiler cannot  
implicitly cast the type returned by MemberwiseClone(), which is "object",  
to the variable being assigned, which is type "BiologySequence".  The  
error also tells you that an explicit cast exists and asks you if you  
forgot to include it.

Which you did.

Put the cast in and it should work fine.

Pete
Ethan Strauss - 10 Jan 2008 15:15 GMT
Hi,
 I can certainly put in the explicit cast to "BiologySequence", but then it
casts as "BiologySequence" rather that the inherited type if I call it from
an inherited class.
I tried
  BiologySequence ToReturn = (this.GetType()) this.MemberwiseClone();
(and some variations) to cast it as the correct type, but I have not be able
to get anything of this sort to work.

Ethan

> > Thanks Peter.
> > I can't get it to compile.
[quoted text clipped - 15 lines]
>
> Pete
Peter Duniho - 10 Jan 2008 18:44 GMT
>   I can certainly put in the explicit cast to "BiologySequence", but  
> then it
> casts as "BiologySequence" rather that the inherited type if I call it  
> from
> an inherited class.

The method returns a BiologySequence, so there's no point in casting it to  
anything else.  That's what the caller is going to see, regardless.

The caller can then cast it to an appropriate type when it receives the  
return value.

You seem to be under the impression that casting will actually change the  
type of the instance.  It doesn't.  Assuming no implicit type conversion  
has been implemented (and in this situation, that is the case), all that  
casting is going to do is change the way the _compiler_ views the object.  
That's all.

So, when you clone the object, the type returned by the method  
MemberwiseClone() is "object", but the instance is already whatever type  
the original instance was.  Likewise, casting it to something else doesn't  
change this...it still remains whatever type the original instance was.  
The casting just allows the compiler to know that the instance can be  
treated as the newly cast type (an exception would occur if the cast was  
invalid at run-time).

> I tried
>    BiologySequence ToReturn = (this.GetType()) this.MemberwiseClone();
> (and some variations) to cast it as the correct type, but I have not be  
> able
> to get anything of this sort to work.

Please look at the sample that I posted.  In a few short lines it  
illustrates everything you need to know about this problem.

Pete
Ethan Strauss - 10 Jan 2008 21:01 GMT
Hi again,
  Actually, your explaination below does help clarify things. It appears
that what I really want (a method called from the base class which, when
called from an inherited class, will relturn an object of that inherited
class type) is not possible. This is all I really need to know. I will have
to write a version of the method for each inherited class.
Ethan
 


> >   I can certainly put in the explicit cast to "BiologySequence", but  
> > then it
[quoted text clipped - 32 lines]
>
> Pete
Peter Duniho - 11 Jan 2008 00:50 GMT
>    Actually, your explaination below does help clarify things. It appears
> that what I really want (a method called from the base class which, when
> called from an inherited class, will relturn an object of that inherited
> class type) is not possible.

That's not true.  It's not only possible, I provided a code example that  
does exactly that.
Ethan Strauss - 11 Jan 2008 18:38 GMT
Hi Peter,
  Maybe I am just being dense, but looking back at your example, again,
does not help.

I have tried this as a direct extrapolation of your code, but it doesn't
compile because the memberwise clone does not know it has a .Sequence
property

      public object Subsequence(int firstBase, int lastBase)
       {
               return this.MemberwiseClone().Sequence.Substring(firstBase,
lastBase - firstBase); ;
       }

I have tried

      public object Subsequence(int firstBase, int lastBase)
       {
           BiologySequence ToReturn = (BiologySequence)
this.MemberwiseClone();
           ToReturn.Sequence = _Sequence.Substring(firstBase, lastBase -
firstBase);
           return ToReturn;
       }
which compiles, gives an error of ("Cannot implicitly convert type
'BiologyTools.BiologySequence' to 'BiologyTools.NucleicAcidSequence'.") for
the next chunk

    NucleicAcidSequence target = new NucleicAcidSequence();

           int firstBase = 0;
           NucleicAcidSequence expected = null;
           NucleicAcidSequence actual;

           actual = target.Subsequence(firstBase);

I have tried various other things. None of them work without an *explicit*
recast after calling the Subsequence method. I was trying to avoid this
explicit recast after calling, but I think that is not possible.

Does that make sense? Am I still missing something?
Thanks,
Ethan
Peter Duniho - 11 Jan 2008 19:52 GMT
>    Maybe I am just being dense, but looking back at your example, again,
> does not help.
[quoted text clipped - 9 lines]
> lastBase - firstBase); ;
>         }

Even if the above code were changed to cast the return from  
MemberwiseClone() to the right type, it'd be returning a String, not a  
BiologySequence or NucleicAcidSequence.  So, no...that's definitely not  
what you want.

> I have tried
>
[quoted text clipped - 6 lines]
>             return ToReturn;
>         }

This is what you want.

>  which compiles, gives an error of ("Cannot implicitly convert type
> 'BiologyTools.BiologySequence' to 'BiologyTools.NucleicAcidSequence'.")  
[quoted text clipped - 7 lines]
>
>             actual = target.Subsequence(firstBase);

Because you need to cast the return value to match the type you know it to  
be.  (I'm ignoring the fact that your call to Subsequence() has only one  
parameter, even though the declared method has two...I assume your actual  
code is more consistent than that).

> [...]
> I have tried various other things. None of them work without an  
> *explicit*
> recast after calling the Subsequence method. I was trying to avoid this
> explicit recast after calling, but I think that is not possible.

You never mentioned a requirement to avoid an explicit recast.  All you've  
ever said is that you want the method to return an object of the correct  
type, and that's exactly what it does.  (Again, the type of a given  
identifier, whether variable, return value, or whatever, is only a  
specifier to the compiler...it does _not_ tell you what the actual type of  
the object is).

I have no idea why that's a requirement, nor do I think it's a good one.  
Just use the second version of the Subsequence() method that you posted,  
and cast the return value.

You can't avoid casting completely, because there's no generic  
MemberwiseClone() method.  But if you really insist on avoiding it in the  
caller, you could do something like this:

    public T Subsequence<T>(int firstBase, int lastBase)
    {
        T ToReturn = (T)this.MemberwiseClone();

        ToReturn.Sequence = Sequence.Substring(firstBase, lastBase -  
firstBase);

        return ToReturn;
    }

then:

    NucleicAcidSequence actual =  
target.Subsequence<NucleicAcidSubsequence>(firstBase, lastBase);

This uses C# generics to allow you to specify a specific type for the  
method to use as its return value.

Personally, I wouldn't see the point in writing the method like that, but  
you could if you wanted to.

Aside: note that I also changed "_Sequence" to "Sequence".  IMHO, if  
you're using a property, you should always use the property.  Hard-coding  
the field the property uses pretty much eliminates one of the main  
benefits of making it a property in the first place.

Pete
Ethan Strauss - 11 Jan 2008 20:26 GMT
Thanks.
I think I have everything working now.
I also think I agree with your comments on avoiding explicit casting. This
is my first major foray into inheritance and I am still working out the
kinks. Thanks for sticking with me
Ethan

> >    Maybe I am just being dense, but looking back at your example, again,
> > does not help.
[quoted text clipped - 93 lines]
>
> Pete
Peter Duniho - 12 Jan 2008 00:41 GMT
> I think I have everything working now.
> I also think I agree with your comments on avoiding explicit casting.  
> This
> is my first major foray into inheritance and I am still working out the
> kinks. Thanks for sticking with me

You're welcome...I'm glad you got it working.  For what it's worth, the  
inheritance issue and the confusion involved isn't uncommon.  I'm still  
not sure exactly at what point you went off the tracks, but this wouldn't  
be the first time that someone posted here confused about what exactly  
casting a reference to an object instance does.  :)

Pete

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.