2010-07-08 4 views
7

J'ai le code suivant et je voudrais l'écrire de manière à avoir un minimum de lignes de code et le travail se fait de la même manière. Comment puis je faire ça?Comment puis-je éviter la duplication de code

List<Category> categoryList = new List<Category>(); 
categoryList = Category.LoadForProject(project.ID).ToList(); 
List<string> categories = new List<string>(Categories); 
IList<Category> currentCategories = Category.LoadForProject(project.ID).ToList(); 
if (currentCategories != null) 
{ 
    foreach (var existingCategories in currentCategories) 
    { 
     if (categories.Contains(existingCategories.Name)) 
      categories.Remove(existingCategories.Name); 
     else 
      existingCategories.Delete(Services.UserServices.User); 
    } 
    foreach (string item in categories) 
    { 
     Category category = new Category(project, item.ToString()); 
     category.Project = project; 
     category.Save(); 
    } 
} 

List<string> priorities = new List<string>(Priorities); 
IList<Priority> currentPriorities = Priority.LoadForProject(project.ID).ToList(); 
if (currentPriorities != null) 
{ 
    foreach (var existingPriorities in currentPriorities) 
    { 
     if (priorities.Contains(existingPriorities.Name)) 
      priorities.Remove(existingPriorities.Name); 
     else 
      existingPriorities.Delete(Services.UserServices.User); 
    } 
    foreach (string item in priorities) 
    { 
     Priority priority = new Priority(project, item.ToString()); 
     priority.Project = project; 
     priority.Save(); 
    } 
} 

Répondre

9

Quelque chose comme ça devrait le faire:

public IList<T> DoYourThing<T>(IList<T> items, IList<T> currentItems, Project project) where T : CommonBaseType 
{ 
    if (currentItems != null) 
    { 
    foreach (var existingItem in currentItems) 
    { 
     if (items.Contains(existingItem.Name)) 
     items.Remove(existingItem.Name); 
     else 
     existingItems.Delete(Services.UserServices.User); 
    } 
    foreach (string item in items) 
    { 
     T newItem = Activator.CreateInstance(typeof(T), new object[] {project, item.ToString()}) as T; 
     newItem.Project = project; 
     newItem.Save(); 
    } 
    } 

    return currentItems; 
} 

Ensuite, vous pouvez l'appeler comme ceci:

var currentCategories = DoYourThing(Categories.ToList(), Category.LoadForProject(project.ID).ToList()); 
var currentProjects = DoYourThing(Priorities.ToList(), Priority.LoadForProject(project.ID).ToList()); 

Enfin, il faut noter deux choses en particulier: En premier lieu, il y a un générique condition sur la fonction where T : CommonBaseType. Je suppose que la catégorie et le projet ont un type de base commun ou une interface qui inclut le nom. Si ce n'est pas le cas, vous devriez vous débarrasser de la condition et utiliser Dynamique pour obtenir le nom. Deuxièmement, j'utilise Activator.Create pour créer la classe pour vous. C'est la partie difficile qui rend difficile à comprendre, si vous ne connaissez pas cette astuce

Bonne chance!

+0

Génériques est une belle solution ... votre appel aurait besoin d'ajouter le type ne le ferait pas, c'est à dire 'var currentCategories = DoYourThing (Categories.ToList(), Category.LoadForProject (project.ID) .ToList()) "? – Lazarus

+0

@Lasarus: Non. Lorsque le type peut être déduit par les paramètres (comme dans ce cas), la déclaration de type sur la méthode est redondante. :) –

+0

@Brian Genisio votre droit qui est incroyablement difficile à trouver si vous ne comprenez pas l'activateur.Créer une partie. C'est un génie simple. – msarchet

7

Marque et Catégorie Priorité implémentent la même interface ou proviennent d'une classe avec les propriétés communes en elle (à savoir .Projet, .Nom et .Save). Ensuite, utilisez cette interface ou classe de base comme type de votre fonction et vous pourrez y passer des collections des deux classes.

+0

Battez-moi ... que diriez-vous de code ... – Lazarus

+0

@Lazarus était à mi-chemin en écrivant du code quand j'ai vu @Brian Genisio a bien illustré le point! – w69rdy

0

Si Priority et Category sont tous deux dérivés de la même classe de base avec un ensemble commun de méthodes/propriétés, ou implémentent la même interface alors oui, vous pouvez. Vous devrez simplement remplacer les références spécifiques par Priority et Category par des références à cette classe de base ou à cette interface (le cas échéant). Il y a quelques différences mineures de code (comme le List<string>(Categories) dans le premier bloc de code) que vous devrez penser à la façon de gérer, mais la majeure partie du code tombera juste en place une fois que la question ancêtre/interface sera réglée.

+0

Je ne pense pas que ce soit un cas d'héritage car la hiérarchie des classes n'aurait aucun sens. Vous pourriez créer une classe de base arbitraire, mais cela ne suivrait pas l'esprit d'être un ancêtre commun aux classes enfant. Une interface a beaucoup plus de sens ici pour fournir une 'API' commune à des classes disparates. – Lazarus

0

Je trouve dynamic très utile pour les ensembles de types qui exposent la même propriété, mais n'implémentent pas la même interface.

Effectuez une itération sur la liste avec foreach(dynamic d in myList)... d.Name..., enroulez-la dans une méthode et transmettez des instances IList<object> différentes (catégories ou priorités).

Nécessite C# 4.0.

+1

Cela ressemble juste à me tromper ;-) –

+0

même que Jouke. c'est juste paresseux ici. dynamique n'est pas prévu que vous n'avez pas besoin de définir des interfaces. – cRichter

+0

Merci, beaucoup pour répondre. Je suis nouveau à C#. Pourriez-vous s'il vous plaît me donner le morceau de code en utilisant dynamique. Merci – learning

0

Vous devez faire priorité et la catégorie proviennent de la même classe de base ... et vous pourriez faire quelque chose le long des lignes de:

public void ProcessLists<ItemType>(Func<int, IEnumerable<ItemType>> Loader) whereItemType : CommonBase, new() { 
List<string> items = new List<string>(); 
IList<ItemType> currentItems = Loader(project.ID).ToList(); 
if (currentItems != null) { 
    foreach (var existingItem in currentItems) { 
     if (items.Contains(existingItem.Name)) 
      items.Remove(existingItem.Name); 
     else 
      existingItem.Delete(Services.UserServices.User); 
    } 
    foreach (string item in items) { 
     ItemType item = new ItemType(); 
     item.Project = project 
     item.Name = item.ToString(); 
     item.Save(); 
    } 
} 

}

Bien sûr, certains types (par exemple comme le projet.ID) sont simplement devinés et devraient être remplacés par les lignes appropriées.

Vous pouvez appeler la fonction de priorité de cette façon:

ProcessLists<Priority>(id => Priority.LoadForProject(project.ID)); 
+0

Avec cette solution, vous êtes bloqué lorsque vous devez appeler un nouveau ItemType, car il doit être différent en fonction du type réel. Les génériques sont la voie à suivre ici. –

+0

@Brian: Hmmm, j'ai peur de ne pas voir ce que vous voulez dire. Pourriez-vous l'expliquer davantage? – Christian

+0

@Christian: Dans ses deux implémentations différentes, il appelle une nouvelle catégorie (args) et un nouveau projet (args). Vous ne pouvez pas simplement appeler un nouveau ItemType(). Vous n'obtiendrez pas le type que vous attendez. Vous devez rendre la méthode générique et appeler Activator.Create (typeof (T), args) pour créer la dérivation correcte de ItemType. –

1

D'accord, aussi loin que je compris, vous voulez ajouter les catégories/priorités de la liste « nouvelle », qui ne sont pas Existant dans le référentiel.

faire cela.

public void SaveNewItems<T>(IList<string> newList, IList<T> currentList, string project) 
    where T: new(), IStoreableItem 
{ 
    //find only new items 
    var toAdd = from itemName in newList 
       where !currentList.Contains(i => i.Name = itemName) 
       select new T { 
        Name = itemName, 
        Project = project 
       }; 


    //find items to delete 
    var toDelete = from item in currentList 
        where !newList.Contains(item.Name) 
        select item; 

    toAdd.ToList().ForEach(item => item.Save()); 
    toDelete.ToList().ForEach(item => item.Delete()); 
} 

catégorie et Prio doivent dériver de IStoreableItem qui contient le nom, le projet et enregistrer/supprimer la méthode.

Questions connexes