1

Have a generic class that inherits from a non-generic class like the structure below:

public class Result
{
     public string ErrorCode { get; set;}
     public string ErrorMessage { get; set;}
     public boo Success { get; set;}
     //Lots more properties

     public ClientResult ToClientResult()
     {
         //some pretty involved calculations of error coded and status
     }
 }

 public class Result<T> : Result
 {
     public T details {get; set;}

     public ClientResult<T> ToClientResult<T>()
     {
        //Need to call the parent class implementation and convert result to  generic ver  
     }
 }

My question is how can i call the parent ToClientResult() and convert the result to the generic version of ClientResult<T> and then i need to set a property of the ClientResult<T> to the details property of the Result<T> class.

I am sure i am missing an easy solution here, i really dont want to duplicate the parent class logic as it is pretty complicated.

शेखर
  • 17,412
  • 13
  • 61
  • 117
Ketchup
  • 3,071
  • 4
  • 20
  • 23
  • 2
    and what is the relation between `ClientResult` and `ClientResult`, and are you allowed to change them as well? – SWeko Jan 30 '13 at 09:21
  • The result is simiar to that of Result and Result and unfortunately i can't change them – Ketchup Jan 30 '13 at 10:06
  • If ClientResult derives from ClientResult, my solution will work. Otherwise you'll have to go with one of the other two mapping-based solutions, which will be more work. – Bennor McCarthy Jan 30 '13 at 10:08

3 Answers3

2

You can't cast an object of the parent type to a child type if it's created as the parent type (using new ClientResult()). It just doesn't work that way.

What you could do is factor the complicated code out to another method which you use to do the heavy lifting in both the Result class and the Result<T> class:

public class Result
{
    public string ErrorCode { get; set;}
    public string ErrorMessage { get; set;}
    public boo Success { get; set;}
    //Lots more properties

     public ClientResult ToClientResult()
     {
         var clientResult = new ClientResult();
         SetupClientResult(clientResult);
         return clientResult;
     }

     protected void SetupClientResult(ClientResult clientResult) 
     {    
         //some pretty involved calculations of error coded and status           
     }

}

public class Result<T> : Result
{
     public T details {get; set;}

     // This now shadows the original ToClientResult method. The trap here is that if
     // you are treating your Result<T> instance as a Result, this method will not be 
     // called, and the return type will be ClientResult and not ClientResult<T>.
     // See: http://stackoverflow.com/questions/392721/difference-between-shadowing-and-overriding-in-c?lq=1
     public ClientResult<T> ToClientResult()
     {
         var clientResult = new ClientResult<T>();
         SetupClientResult(clientResult);

         clientResult.SomeProperty = details;

         return clientResult;
     }
}

This is all assuming ClientResult<T> derives from ClientResult, which is a little hard to tell from your question.

Bennor McCarthy
  • 11,415
  • 1
  • 49
  • 51
  • if the object isn't created using `new ClientResult()` it won't be of that type. The variable might be declared as that type and assigned an object of a derived type but that's different so your first statement makes little sense. You can't cast an `object` to a different type. You can only convert it. Casting doesn't change the type of the `object` only the type of the expression at compile time (objects don't exist compile time but only run time) – Rune FS Jan 30 '13 at 09:36
  • If ClientResult derives from ClientResult, an object of type ClientResult is a ClientResult. It just doesn't work the other way round: an object created as a ClientResult can never be a derived type. Reread what I said. – Bennor McCarthy Jan 30 '13 at 09:47
  • I'm sure you meant the right thing and simply wrote something that confuses object type (runtime) and expression type (compile time). Objects exist at runtime only and in C# (in contrast to E.g. Ruby) you can't change the type of an object. You can tell the compiler that a given expression though declared as type `base` is actually going to return an object of type `derived` which is called casting (down-casting in this particular example) the object type is _not_ changed by a cast – Rune FS Jan 30 '13 at 09:53
  • I'm not confusing anything. It doesn't matter that the underlying type is still the derived type. I realise that my solution involves upcasting when passing the object to the protected method, but that's kind of the point. – Bennor McCarthy Jan 30 '13 at 09:56
  • I think you're also missing the point of the question. You're answering the exact wording (i.e. "how do I convert parent object to child object") without thinking about the intent (i.e. "I want to return a derived type from my derived class while reusing the work I did in the base class"). – Bennor McCarthy Jan 30 '13 at 10:02
  • Thank you for taking the time to answer this for me. Exactly what i was looking for. Seems very simple now thought. – Ketchup Jan 30 '13 at 10:20
  • You will need to pay attention to my comments on shadowing and be careful about how you're calling `ToClientResult()`. – Bennor McCarthy Jan 30 '13 at 10:21
  • @BennorMcCarthy as I stated it's a comment to the wording in the first sentence it had nothing to do with the intend of the answer. Which is why I didn't comment on anything than the pleonasm in the first sentence but it seems pointless to continue that discussion – Rune FS Jan 30 '13 at 11:12
0

in the ClientResult<T> class you could make a custom conversion from ClientResult to ClientResult<T>

public static explicit operator ClientReault<T>(ClientResult result)
{
       //do your conversion from one to the other here
}

you could then write ToClientResult like this

 //Generic argument remove from method declaration
 //because it was shadowing the type argument
 public ClientResult<T> ToClientResult()
 {
    var clientResult = ((Result)this).ToClientResult()
    var genericResult = (ClientResult<T>)clientResult;
    //do what you need to do with the generically typed object
    //...
    return genericResult
 }

That said this situations often arises when there's a flaw in the inheritance chain. E.g. when there's no is-a relationship between the base and derived class

Rune FS
  • 21,497
  • 7
  • 62
  • 96
0

You should explicitly do the conversion:

    public class ClientResult
    {
        public int a {get;set;}
    }

    public class ClientResult<T> : ClientResult
    {
        public ClientResult(ClientResult cr)
        {
            this.a = cr.a;
        }
    }

    public class Result<T> : Result
    {
        public T details { get; set; }

        public ClientResult<T> ToClientResult<T>()
        {
            var cr = base.ToClientResult();
            return new ClientResult<T>(cr);  
        }
    }

In case you have a lot of classes similar to ClientResult, you could use a tool like AutoMapper

phnkha
  • 7,782
  • 2
  • 24
  • 31