2009-03-29 5 views
1

J'ai une classe comme ceci:dans .NET en utilisant transtypage ascendant génériques

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

Cette classe est alors héritée par un groupe de classes générées, par exemple:

public class B : A { 
    ... 
} 

La base int Le constructeur n'est pas exposé à la classe héritée (pour des raisons de conception, je ne veux pas qu'il soit exposé). Dans ma bibliothèque qui contient la définition de la classe A j'ai une méthode comme ceci:

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

Et puis je l'utiliser comme ceci:

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

Depuis le constructeur que je veux utiliser n'est pas exposé à la classe B quand je fais typeof(T).GetConstructor(typeof(int)) Je ne rentre pas le constructeur, donc je veux penser que je ferais ceci:

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

Mais cela me donne un ru Erreur de temps System.InvalidCastException, que je ne peux pas convertir un type A en type B.

Comment puis-je procéder à cette surenchère?

Répondre

3

Vous pouvez simplement utiliser des constructeurs par défaut afin de pouvoir instancier des objets de type T avec la contrainte new(). Alors la classe A peut avoir une méthode virtuelle (ou abstraite à votre goût) qui prend un int comme argument et initialise l'objet après que le constructeur ait couru.

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; 
} 

Si vous avez l'intention une sorte de modèle d'usine, vous n'avez pas besoin d'hésiter d'initialisation parties d'un objet en dehors de l'appel du constructeur tant que cela est fait avant de retourner l'objet au contrôle de l'appelant.

+0

Oui, c'est ce que je vais faire maintenant. Fonctionne bien –

1

D'après ce que je compris, T dérive d'un, de sorte que vous ne pouvez pas lancer A à T.

+0

Il est plus logique de dire: Bien que T dérive de A, vous ne pouvez pas lancer une instance de A vers T; aucune instance de A n'est un T, mais n'importe quelle instance de T est un A (à moins que vous ne comptiez les T qui sont en réalité des A et non des types strictement dérivés). –

+0

Yup, c'est ce que je voulais dire. Mais vous l'avez exprimé plus clairement :) – Philippe

+0

Comment fonctionne la conversion de WebRequest en HttpWebRequest dans ce cas? –

1

Vous ne pouvez pas transtyper A à B dans votre exemple, parce que:

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

Instantiates a A, qui est et non a B. Tout simplement parce que "B est un A" ne signifie pas "A est un B". Vous devez d'abord instancier un B, le convertir en A, faire ce que vous voulez, puis le réattribuer à un B.

Je ne sais pas si cela va être compilé, mais vous pouvez essayer ceci:

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; 

Tenir compte Remanier contructor tel que vous initialisez l'entier comme une propriété, au lieu d'un paramètre du constructeur. Je m'efforce d'avoir des contructeurs par défaut (sans paramètres) afin que le code générique puisse facilement instancier la classe.

0

Vous ne pouvez pas faire cela, changer votre conception.

Questions connexes