Bonjour,
J'ai un problème de design, car visiblement C# ne permet pas de répondre à mon problème.
La notion d'héritage et de polymorphisme ne concerne que les "instances" pas les "types" directement.
Ainsi, mon idée de départ d'avoir une méthode statique abstraite dans ma classe de base, dérivée ensuite dans chaque classe dérivée ne fonctionne pas.
Et du coup je cherche une solution élégante pour contourner le problème proprement.
Le besoin initial :
J'ai deux classes "Customer" et "Project".
Ces deux classes correspondent à des données en base.
Je vais notamment faire des opérations de CRUD dessus.
J'ai donc créé une classe de base "Crud" qui permet d'appeler des procédures stockées de Creation, Retrieve, Update et Delete.
J'ai ensuite hérité de cette classe pour implémenter aisément la couche d'accès aux données dans mes classes Customer et Project.
Tout marche plutôt pas mal quand je suis sur une instance (donc Creation, Update et Delete ne posent pas de problème quand il s'agit de faire une ligne à ligne) mais lorsque je travaille sur une méthode statique, c'est tout autre-chose : pas moyen de rériver une méthode statique.
Malheureusement, "Retrieve" retourne par essence un List<T> et non une unique instance de T.
Et quand on cherche quelque chose, généralement c'est qu'on en a pas déjà sous la main... Donc créer une instance "coquille vide" juste pour pouvoir charger la liste des éléments recherches me pose clairement un problème de principe.
Du coup, j'ai dû feinter : ma classe de base implémente une méthode statique "protected".
Et mes classes filles implémentent une méthode statique "public" qui appelle la méthode de base (après avoir fait quelques bidouilles) :
Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public abstract class Crud<T> public Crud() { } public static List<T> LoadAllFromDatabase(string procedure) { List<T> items = new List<T>(); using (SqlConnection cnx = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyCnx"].ConnectionString)) { cnx.Open(); using (SqlCommand cmd = cnx.CreateCommand()) { cmd.CommandText = procedure; cmd.CommandType = CommandType.StoredProcedure; SqlDataReader dr = cmd.ExecuteReader(); while (dr.Read()) { object[] values = new object[dr.FieldCount]; dr.GetValues(values); items.Add((T)typeof(T).GetMethod("FromDatabase").Invoke(null, new object[] { values })); } dr.Close(); } cnx.Close(); } return items; } } public class Customer : Crud<Customer> { public int ID { get; private set; } public string Name { get; set; } public Customer() { } public static Customer FromDatabase(object[] values) { return new Customer() { ID = (int)values[0], Name = (string)values[1] }; } public static List<Customer> LoadAllFromDatabase() { return LoadAllFromDatabase("GetAllCustomers"); } public static int Create(Customer customer) { throw new NotImplementedException(); } public void Update() { throw new NotImplementedException(); } public void Delete() { throw new NotImplementedException(); } }
Ce code me pose deux problèmes :
1/ Je n'ai pas de "contrat" pour imposer que toutes les classes dérivées de Crud implémentent la méthode statique List<T> LoadAllFromDatabase() afin de garantir un code cohérent d'une classe dérivée à l'autre (et pouvoir utiliser mes instances dérivées dans d'autre classes qui manipulent des Crud sans connaître le type de base).
2/ Je n'ai pas non plus de "contrat" pour imposer que toutes les classes dérivées de Crud implémentent la méthode statique <T> FromDatabase() alors que cette méthode est appelée en dur dans ma classe de base via réflexion. Et accessoirement, la réflexion me donne des boutons : à la base, je vois ça comme un contournement d'un mauvais design... Sans oublier que je ne suis pas certain que ça ne soit pas une usine à gaz à exécuter.
Comment gèreriez-vous le problème, vous ?
Partager