Considérez ces méthodes:
public List<Employee> GetAllEmployees()
{
using (Entities entities = new Entities())
{
return entities.Employees.ToList();
}
}
public List<Job> GetAllJobs()
{
using (Entities entities = new Entities())
{
return entities.Jobs.ToList();
}
}
public List<Task> GetAllTasksOfTheJob(Job job)
{
using (Entities entities = new Entities())
{
return entities.Tasks.Where(t => t.JobId == job.Id).ToList();
}
}
L'utilisation de block est la même et a été répétée 3 fois ici (bien sûr, plus de 100 fois dans l'application réelle). Comment est-il possible d'implémenter le principal DRY (Don't Repeat Yourself) pour le using
bloc? Est-ce considéré comme une violation du principe DRY?
Mise à jour: je ne parle pas de ce qui a été implémenté à l'intérieur du using
bloc. Ce que je veux dire ici, c'est le using (Entities entities = new Entities())
. Cette ligne est répétée 100 fois ou plus.
c#
design-patterns
dry
Saeed Neamati
la source
la source
Réponses:
Une idée serait de l'envelopper avec une fonction qui prend a
Func
.Quelque chose comme ça
Ensuite, votre code ci-dessus devient
J'ai également fait
Entities
un paramètre de type, car je suppose que vous avez plus d'un type avec lequel vous faites cela. Si ce n'est pas le cas, vous pouvez le supprimer et utiliser simplement le paramètre de type pour le type de retour.Pour être honnête, ce type de code n'aide en rien la lisibilité. D'après mon expérience, plus de collègues Jr ont également de la difficulté à le faire.
Mise à jour Quelques variantes supplémentaires sur les aides que vous pourriez envisager
la source
Entities
.IEnumerable
côté la fonction au cas où il y aurait des non-IEnumerable
propriétés de T que l'appelant voulait renvoyer, mais vous avez raison, cela nettoierait un peu. IlIEnumerable
serait peut-être bon d' avoir un assistant pour le single et les résultats. Cela dit, je pense toujours que cela ralentit la reconnaissance de ce que fait le code, en particulier pour quelqu'un qui n'est pas habitué à utiliser beaucoup de génériques et de lambdas (par exemple, vos collègues qui ne sont PAS sur SO :))WithEntities
, utilisez à laFunc<T,IEnumerable<K>>
place deFunc<T,K>
et donnez à "WithEntities" un meilleur nom (comme SelectEntities). Et je ne pense pas que "Entités" doive être un paramètre générique ici.where T : IDisposable, new()
, comme l'using
exigeIDisposable
, pour fonctionner.Pour moi, cela reviendrait à s'inquiéter de devoir répéter plusieurs fois la même collection: c'est juste quelque chose que vous devez faire. Toute tentative de l'abréger rendrait le code beaucoup moins lisible.
la source
foreach
est sur une très grande collection ou si la logique dans laforeach
boucle prend du temps par exemple. Une devise que j'en suis venue à adopter: n'observez pas mais soyez toujours attentif à votre approcheOn dirait que vous confondez le principe "Une seule et unique fois" avec le principe DRY. Le principe DRY stipule:
Cependant, le principe Once and Only Once est légèrement différent.
Le principe DRY est généralement utilisé dans le contexte d'une logique réelle, pas tellement redondant à l'aide d'instructions:
La source
la source
Je ne vois pas l'utilisation d'
using
ici:Que diriez-vous:
Ou encore mieux, car je ne pense pas que vous ayez besoin de créer un nouvel objet à chaque fois.
En ce qui concerne la violation de DRY: DRY ne s'applique pas à ce niveau. En fait, aucun principe ne le fait vraiment, sauf celui de la lisibilité. Essayer d'appliquer DRY à ce niveau n'est en réalité que de la micro-optimisation architecturale, qui, comme toute micro-optimisation, n'est qu'un délestage de vélo et ne résout aucun problème, mais risque même d'en introduire de nouveaux.
D'après ma propre expérience, je sais que si vous essayez de réduire la redondance du code à ce niveau, vous créez un impact négatif sur la qualité du code, en obscurcissant ce qui était vraiment clair et simple.
Edit:
Ok. Ainsi, le problème n'est pas réellement l'instruction using, le problème est la dépendance à l'objet que vous créez à chaque fois. Je suggère d'injecter un constructeur:
la source
using (CustomTransaction transaction = new CustomTransaction())
bloc de code dans notre code pour définir la portée d'une transaction. Cela ne peut pas être regroupé en un seul objet et à chaque endroit où vous souhaitez utiliser une transaction, vous devez écrire un bloc. Maintenant, que se passe-t-il si vous souhaitez modifier le type de cette transaction deCustomTransaction
àBuiltInTransaction
plus de 500 méthodes? Cela me semble être une tâche répétitive et un exemple de violation du principal DRY.using
(dans ce contexte) est une "syntaxe pratique" plus inconnue? Pourquoi c'est si agréable à utiliser =)Non seulement l'utilisation est du code en double (d'ailleurs, c'est du code en double et se compare en fait à une instruction try..catch..finally) mais aussi la toList. Je voudrais refactoriser votre code comme ceci:
la source
Puisqu'il n'y a ici aucune logique commerciale, à l'exception de la dernière. Ce n'est pas vraiment SEC, à mon avis.
Le dernier n'a pas de DRY dans le bloc using mais je suppose que la clause where devrait changer où qu'elle soit utilisée.
Il s'agit d'un travail typique pour les générateurs de code. Écrire et couvrir le générateur de code et le laisser générer pour chaque type.
la source
using (Entities entities = new Entities())
bloc. Je veux dire, cette ligne de code est répétée 100 fois et se répète de plus en plus.Puisque vous créez et détruisez le même objet jetable encore et encore, votre classe est elle-même un bon candidat pour implémenter le modèle IDisposable.
Cela vous laisse seulement besoin de «utiliser» lors de la création d'une instance de votre classe. Si vous ne voulez pas que la classe soit responsable de l'élimination des objets, vous pouvez faire en sorte que les méthodes acceptent la dépendance comme argument:
la source
Mon morceau préféré de magie incompréhensible!
Wrap
n'existe que pour en faire abstraction ou quelle que soit la magie dont vous avez besoin. Je ne suis pas sûr de le recommander tout le temps, mais il est possible de l'utiliser. La "meilleure" idée serait d'utiliser un conteneur DI, comme StructureMap, et d'étendre simplement la classe Entities au contexte de la demande, de l'injecter dans le contrôleur, puis de le laisser s'occuper du cycle de vie sans que votre contrôleur n'en ait besoin.la source
Func
suffisamment.