3 votes

Est-il possible de passer la sous-classe de la super-classe dans <T> ?

J'ai une classe nommée GenericDao

internal class GenericDao<T> : IGenericDao<T> {
}

Les deux classes d'objets :

public class Empresa {
}

public class Assessoria : Empresa {
}

Et j'ai un EmpresaDao :

public class EmpresaDao {

    private GenericDao<Empresa> parent { get; set; }

    public EmpresaDao() {
        this.parent = new GenericDao<Empresa>();
    }
}

Comment instancier le GenericDao en utilisant la sous-classe Assessoria ? Je fais quelque chose comme ça, mais ne fonctionne pas :

public class EmpresaDao {

    private GenericDao<Empresa> parent { get; set; }

    public EmpresaDao(Type type) {
        if (type == typeof(Assessoria)) {
            this.parent = new GenericDao<Assessoria>();
        } else {
            this.parent = new GenericDao<Empresa>();
        }
    }
}

2voto

siride Points 36602

En bref, vous ne pouvez pas, vraiment. Cependant, vous pouvez tricher un peu si vous utilisez une interface de base qui n'est pas générique, ou si vous utilisez C# 4 et utilisez une interface de base qui est générique, mais avec un paramètre de type covariant ou contravariant (selon le besoin). Pour le premier cas :

interface IGenericDaoBase {
}

interface IGenericDao<T> : IGenericDaoBase {
}

public class EmpresaDao {
    private IGenericDaoBase parent { get; set; }
    public EmpresaDao(Type type) {
        // same as before
    }
}

Certes, il serait peut-être préférable de repenser votre conception. Peut-être que EmpresaDao peut prendre un paramètre générique lui-même, qui serait utilisé comme ceci :

public class EmpresaDao<T> where T : Empresa {
    private GenericDao<T> parent { get; set; }
    public EmpresaDao() {
        this.parent = new GenericDao<T>();
    }
}

EDIT : En fait, plus j'y pense, plus je crois que cette dernière solution est la meilleure. Le paramètre de type dans le constructeur remplit le même rôle que le paramètre de type dans la signature de la classe. Vous n'aurez donc pas à modifier le code d'appel, sauf pour passer un paramètre générique au lieu d'un objet Type.

1voto

Ali Ferhat Points 1566

C'est une bonne chose que votre essai ne fonctionne pas, vous introduiriez un bug si c'était le cas.

Supposons que j'ai des variables a , b tous deux de type EmpresaDao . a est paraphé avec un Empresa parent et b est initialisé avec un Assessoria parent. Puisque a y b sont du même type, il devrait être possible d'utiliser l'un à la place de l'autre partout. Supposons que Assessoria mais pas Empresa a une méthode assess() . Mais vous attendez b.parent à être Assessoria donc vous voulez appeler b.parent.assess() mais vous ne pouvez pas appeler a.parent.assess() Ce qui signifie a y b ne devraient pas être du même type en premier lieu.

La solution dépend de si vous allez appeler .parent.assess() :

a) Si vous n'appelez jamais .parent.assess() sur EmpresaDao le type du parent au moment de la compilation est toujours le suivant Empresa . Voici une solution :

public class EmpresaDao
{
    private Empresa parent {get; set; }
    public EmpresaDao(Func<Empresa> parentConstructor)
    {
        this.parent = parentConstructor();    
    }
}    
static main()
{
    var withEmpresaParent = new EmpresaDao(() => new Empresa());
    var withAssessoriaParent = new EmpresaDao(() => new Assessoria());
    ..
}

b) Vous appellerez parfois .parent.assess() dans la classe EmpresaDao. Ensuite, vous devez rendre l'EmpresaDao générique, comme l'a dit @siride :

public class EmpresaDao<T> where T : Empresa
{
    private T parent {get; set;}
}

Cependant, vous devrez toujours effectuer des vérifications au moment de l'exécution sur le parent avant d'appeler la fonction .parent.assess() Ce qui signifie qu'il y a encore quelque chose qui cloche dans votre conception. Mais il n'y a pas assez d'informations pour décider quoi. Peut-être .assess() doit être privée et ne pas être appelée de l'extérieur (c'est-à-dire que la méthode Assessoria doit être un décorateur sur Empresa : sous-classe mais avec la même interface) Peut-être " Empresa tenant EmpresaDao " et " Assessoria tenant EmpresaDao "devraient être deux classes différentes. (implémentant la même interface, probablement)

Edit : Maintenant je me rends compte que, dans ma solution, j'ai fait par erreur le type du parent Empresa ou Assessoria au lieu de GenericDao ou GenericDao. Je pense que ma solution principale est toujours valable cependant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X