1

So I've got a class like this:

public class A { 
  internal A(int i) { ... }
  public int Foo { get; set; }
}

This class is then inherited by a bunch of generated classes, eg:

public class B : A {
  ...
}

The int based constructor isn't exposed to the inherited class (for design reasons I don't want it exposed). In my library which holds the definition for class A I've got a method like this:

public T Load<T>() where T : A {
  //do some stuff, create an instance of T from an int, then return it
}

And then I'd use it like this:

B b = Helper.Load<B>();

Since the constructor I want to use isn't exposed to class B when I do typeof(T).GetConstructor(typeof(int)) I don't get the constructor back, so I want thinking that I'd do this:

return (T)new A(/*some int */);

But that gives me a runtime error System.InvalidCastException, that I can't cast a type A to type B.

How do I go about achieving this upcasting?

Aaron Powell
  • 24,927
  • 18
  • 98
  • 150

4 Answers4

3

You can just use default constructors so you can instantiate objects of type T with the new() constraint. Then class A can have a virtual (or abstract to your liking) method that takes an int as an argument and initializes the object after the constructor has run.

public class A {
    internal A() { }
    internal Initialize(int i) { Foo = i; }
    public int Foo { get; set; }
}

public class B : A { 
    internal B() { }
}

...

public T Load<T>() where T : A, new() {
    var ret = new T();
    ret.Initialize(i);
    return ret;
}

If you intend some sort of factory pattern, you don't need to hesitate initializing parts of an object outside the constructor call as long as it is done before you return the object to the caller's control.

Cecil Has a Name
  • 4,962
  • 1
  • 29
  • 31
1

From what I understood, T derives from A, so you can't cast A to T.

Philippe
  • 3,945
  • 3
  • 38
  • 56
  • It makes more sense to say: Although T derives from A, you cannot cast an instance of A to T; no instance of A is a T, but any instance of T is an A (unless you count the T's that are actually A's and not strictly derived types). – Cecil Has a Name Mar 29 '09 at 11:14
  • Yup, that's what I meant. But you expressed it more clearly :) – Philippe Mar 30 '09 at 07:02
  • How does converting WebRequest to HttpWebRequest works in that case? – Apurv Gupta Jan 28 '17 at 09:35
1

You can't upcast A to B in your example, because:

return (T)new A(/*some int */);

Instantiates an A, which is not a B. Just because a "B is an A" does not mean "A is a B". You would have to first instantiate a B, cast it to an A, do what you want, and then upcast it back to a B.

I'm not sure if this is will compile, but you could try this:

T blah = new T(5); //this means your B will need to implement a int constructor
A blah2 = (A)blah;
//operate on A specific operations in blah2
T upcasted = (T)blah2;
//alternatively
T upcasted = blah2 as T;

Consider refactoring your contructor such that you initialize the integer as a property, instead of a parameter of the constructor. I strive to have default(no parameters) contructors so that generic code can instantiate the class easily.

AaronLS
  • 37,329
  • 20
  • 143
  • 202
0

You cant do this, change your design.

Brijesh Mishra
  • 2,738
  • 1
  • 21
  • 36